weifuwu 0.90.0 → 0.91.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.
- package/README.md +4 -2
- package/dist/client/components/WordCloud/WordCloud.d.ts +79 -0
- package/dist/client/components/index.d.ts +2 -0
- package/dist/client/components/index.js +33 -33
- package/dist/client/components/style.css +95 -1
- package/dist/client/layout/weifuwu-layout.css +19 -0
- package/dist/client/vdom/core/v2/diff.d.ts +2 -2
- package/dist/client/vdom/hooks/env.d.ts +20 -0
- package/dist/client/vdom/index.js +3 -3
- package/dist/client/vdom/testing.js +2 -2
- package/dist/server/ai/approvals.d.ts +24 -0
- package/dist/server/ai/assemble.d.ts +19 -0
- package/dist/server/ai/client.d.ts +22 -0
- package/dist/server/ai/contracts.d.ts +67 -2
- package/dist/server/ai/index.d.ts +14 -43
- package/dist/server/ai/memory-server.d.ts +50 -0
- package/dist/server/ai/memory.d.ts +46 -0
- package/dist/server/ai/multimodal.d.ts +52 -0
- package/dist/server/ai/openai.d.ts +16 -0
- package/dist/server/db/body.d.ts +31 -0
- package/dist/server/db/consistency.d.ts +28 -0
- package/dist/server/db/contracts.d.ts +3 -27
- package/dist/server/db/filter.d.ts +24 -0
- package/dist/server/db/gql-from-shape.d.ts +42 -0
- package/dist/server/db/http.d.ts +38 -0
- package/dist/server/db/memory-sql.d.ts +66 -8
- package/dist/server/db/ops.d.ts +70 -0
- package/dist/server/db/orm.d.ts +110 -0
- package/dist/server/db/query-builder.d.ts +4 -2
- package/dist/server/db/query.d.ts +90 -32
- package/dist/server/db/rest-from-shape.d.ts +56 -0
- package/dist/server/db/schema.d.ts +78 -0
- package/dist/server/db/server.d.ts +0 -2
- package/dist/server/db/shape.d.ts +131 -0
- package/dist/server/db/typed-query.d.ts +113 -0
- package/dist/server/email/api.d.ts +15 -0
- package/dist/server/email/contracts.d.ts +8 -3
- package/dist/server/email/index.d.ts +23 -30
- package/dist/server/email/memory-email-server.d.ts +43 -0
- package/dist/server/email/memory-email.d.ts +30 -0
- package/dist/server/index.d.ts +33 -10
- package/dist/server/index.js +9843 -4133
- package/dist/server/messager/index.d.ts +133 -12
- package/dist/server/postgres/client.d.ts +4 -4
- package/dist/server/postgres/types.d.ts +33 -13
- package/dist/server/redis/types.d.ts +2 -0
- package/dist/server/response.d.ts +3 -3
- package/dist/server/types.d.ts +2 -5
- package/dist/server/user/app-auth.d.ts +74 -0
- package/dist/server/user/index.d.ts +277 -5
- package/dist/server/workflow/contracts.d.ts +202 -0
- package/dist/server/workflow/expression.d.ts +89 -0
- package/dist/server/workflow/index.d.ts +70 -0
- package/dist/server/workflow/index.js +2476 -0
- package/dist/server/workflow/runner.d.ts +19 -0
- package/dist/server/workflow/std.d.ts +27 -0
- package/dist/server/workflow/steps.d.ts +12 -0
- package/dist/server/workflow/store.d.ts +19 -0
- package/dist/server/workflow/tojs.d.ts +28 -0
- package/dist/server/workflow/validate.d.ts +23 -0
- package/dist/server/workflow/views.d.ts +66 -0
- package/dist/server/workflow/wfjs.d.ts +27 -0
- package/dist/server/workflows/cron.d.ts +16 -0
- package/dist/server/workflows/index.d.ts +267 -0
- package/dist/shared/zod.d.ts +351 -0
- package/docs/client.md +6 -0
- package/docs/server.md +455 -11
- package/package.json +9 -3
- package/dist/server/db/postgres-server.d.ts +0 -39
- package/dist/server/db/sql-parser.d.ts +0 -24
- package/dist/server/db/test-servers.d.ts +0 -21
- package/dist/server/email/smtp.d.ts +0 -34
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type MemoryAiOptions } from './memory.ts';
|
|
2
|
+
import type { AiClient } from './client.ts';
|
|
3
|
+
export interface MemoryAiServerOptions extends MemoryAiOptions {
|
|
4
|
+
/** 监听端口(0 = 随机——默认)。 */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** 自定义后端(默认 createMemoryAi(options)——决策注入透传) */
|
|
7
|
+
ai?: AiClient;
|
|
8
|
+
/** 请求级注入(测试对 HTTP 面全控——替代自建 fake server):
|
|
9
|
+
* undefined = 走默认 handler(onChat/onEmbed 决策)
|
|
10
|
+
* { status, body } = 故障注入(401/429/5xx)
|
|
11
|
+
* { sse } = 原始 SSE 字节行(tool_calls 分片/坏流/半流)
|
|
12
|
+
* { hang } = 挂起(不响应——首 token 超时/abort 测试) */
|
|
13
|
+
respond?: (req: MemoryAiRequest) => MemoryAiRespond | undefined;
|
|
14
|
+
}
|
|
15
|
+
/** 已接收请求(断言传输细节——路径/认证/体) */
|
|
16
|
+
export interface MemoryAiRequest {
|
|
17
|
+
method: string;
|
|
18
|
+
path: string;
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
body: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/** 注入响应描述 */
|
|
23
|
+
export type MemoryAiRespond = {
|
|
24
|
+
status: number;
|
|
25
|
+
body?: unknown;
|
|
26
|
+
} | {
|
|
27
|
+
sse: string[];
|
|
28
|
+
} | {
|
|
29
|
+
hang: true;
|
|
30
|
+
} | {
|
|
31
|
+
sse: string[];
|
|
32
|
+
hang: true;
|
|
33
|
+
};
|
|
34
|
+
/** 正名构造(new MemoryAiServer() / MemoryAiServer() / createMemoryAiServer() 等价——async 返回 Handle) */
|
|
35
|
+
export interface MemoryAiServer {
|
|
36
|
+
new (options?: MemoryAiServerOptions): Promise<MemoryAiServerHandle>;
|
|
37
|
+
}
|
|
38
|
+
export interface MemoryAiServerHandle {
|
|
39
|
+
port: number;
|
|
40
|
+
/** 完整 base URL(http://127.0.0.1:{port}——给 baseUrl 指向) */
|
|
41
|
+
url: string;
|
|
42
|
+
/** 已接收请求记录(断言用——含 respond 注入的请求) */
|
|
43
|
+
requests: MemoryAiRequest[];
|
|
44
|
+
/** 强制断开所有连接(hang 场景清理) */
|
|
45
|
+
closeAllConnections(): void;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/** 工厂(= MemoryAiServer 正名——createMemoryAiServer 兼容别名) */
|
|
49
|
+
export declare const createMemoryAiServer: typeof MemoryAiServer;
|
|
50
|
+
export declare function MemoryAiServer(options?: MemoryAiServerOptions): Promise<MemoryAiServerHandle>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type AiClientModule } from './assemble.ts';
|
|
2
|
+
import type { StreamFinishResult } from './client.ts';
|
|
3
|
+
import type { ChatParams, ToolCall } from './types.ts';
|
|
4
|
+
import type { ImageGenRequest, ImageGenResult, VideoGenRequest, VideoGenStatus } from './contracts.ts';
|
|
5
|
+
/** MemoryAi 决策注入选项(= MemorySql 的「解析器」——注入方决定回什么) */
|
|
6
|
+
export interface MemoryAiOptions {
|
|
7
|
+
/**
|
|
8
|
+
* 决策注入:chat 请求 → 响应内容。不注入 = 默认 echo(末条 user 消息)。
|
|
9
|
+
* 返回 shape:{ content, toolCalls?, reasoning_content?, usage? }
|
|
10
|
+
* (工具决策:e2e 测试注入 tool_calls 序列——无需真实 LLM)
|
|
11
|
+
*/
|
|
12
|
+
onChat?: (params: ChatParams) => Promise<{
|
|
13
|
+
content: string;
|
|
14
|
+
toolCalls?: ToolCall[];
|
|
15
|
+
reasoning_content?: string;
|
|
16
|
+
usage?: StreamFinishResult['usage'];
|
|
17
|
+
}> | {
|
|
18
|
+
content: string;
|
|
19
|
+
toolCalls?: ToolCall[];
|
|
20
|
+
reasoning_content?: string;
|
|
21
|
+
usage?: StreamFinishResult['usage'];
|
|
22
|
+
};
|
|
23
|
+
/** 嵌入注入(返回值需 text 长度 = 输入顺序);默认 djb2 哈希向量(确定性) */
|
|
24
|
+
onEmbed?: (texts: string[]) => Promise<number[][]> | number[][];
|
|
25
|
+
/** 图片生成注入(测试断言生成面);默认 1×1 透明 PNG data URL(确定性占位) */
|
|
26
|
+
onImage?: (req: ImageGenRequest) => Promise<ImageGenResult> | ImageGenResult;
|
|
27
|
+
/** 视频任务注入(onVideoSubmit: 提交→taskId;onVideoStatus: 查询→状态)——默认立即完成 */
|
|
28
|
+
onVideoSubmit?: (req: VideoGenRequest) => Promise<{
|
|
29
|
+
taskId: string;
|
|
30
|
+
}> | {
|
|
31
|
+
taskId: string;
|
|
32
|
+
};
|
|
33
|
+
onVideoStatus?: (taskId: string) => Promise<VideoGenStatus> | VideoGenStatus;
|
|
34
|
+
/** 默认模型名(响应回显——对齐真实 provider 行为) */
|
|
35
|
+
defaultModel?: string;
|
|
36
|
+
/** 审批超时 ms(默认 5 分钟——对齐 OpenAI transport) */
|
|
37
|
+
approvalTimeoutMs?: number;
|
|
38
|
+
}
|
|
39
|
+
/** 模块构造(new MemoryAi() / MemoryAi() / createMemoryAi() 等价——同 ai() 返回形态:
|
|
40
|
+
* AiClientModule——app.use 注入 ctx.ai + 全能力)。参考 MemorySql 的工厂包装 */
|
|
41
|
+
export interface MemoryAi {
|
|
42
|
+
new (options?: MemoryAiOptions): MemoryAi;
|
|
43
|
+
}
|
|
44
|
+
export declare function MemoryAi(options?: MemoryAiOptions): AiClientModule;
|
|
45
|
+
/** 工厂别名(= MemoryAi——与 createMemorySql 命名对称;主包导出) */
|
|
46
|
+
export declare const createMemoryAi: typeof MemoryAi;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu AI — 多模态 provider(DashScope 百炼)——拆分为独立工厂:
|
|
3
|
+
*
|
|
4
|
+
* createDashscopeImage(opts?) → 图片生成(generateImage——独立 baseUrl/apiKey/model)
|
|
5
|
+
* createDashscopeVideo(opts?) → 视频任务(createVideoTask + videoStatus——独立配置)
|
|
6
|
+
*
|
|
7
|
+
* 与 embedding 平级(AiClientOptions.image / .video 各自独立——可不同端点/不同 key/
|
|
8
|
+
* 不同模型——方便后续配置不同供应商)。参数归一在 provider 层单源:
|
|
9
|
+
* 图片:size 白名单(N*N 形态);视频:RESOLUTIONS/RATIOS 白名单 + duration 夹紧
|
|
10
|
+
* 3-15 + watermark 默认 true。
|
|
11
|
+
*
|
|
12
|
+
* 配置:显式参数 > env(DASHSCOPE_API_KEY / DASHSCOPE_MAAS_API_URL / DASHSCOPE_IMAGE_MODEL /
|
|
13
|
+
* DASHSCOPE_VIDEO_MODEL——URL 均为完整 https 前缀——不做协议补全)。
|
|
14
|
+
*/
|
|
15
|
+
import type { ImageGenRequest, ImageGenResult, VideoGenRequest, VideoGenStatus } from './contracts.ts';
|
|
16
|
+
/** 图片生成 provider 配置(独立于视频——可不同端点/键/模型) */
|
|
17
|
+
export interface ImageGenOptions {
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
/** 完整 URL(https 开头——默认 DASHSCOPE_MAAS_API_URL;测试环境可 http) */
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
/** 默认 DASHSCOPE_IMAGE_MODEL ?? 'z-image-turbo' */
|
|
22
|
+
model?: string;
|
|
23
|
+
}
|
|
24
|
+
/** 视频生成 provider 配置(独立于图片) */
|
|
25
|
+
export interface VideoGenOptions {
|
|
26
|
+
apiKey?: string;
|
|
27
|
+
/** 完整 URL(https 开头——默认 DASHSCOPE_MAAS_API_URL;测试环境可 http) */
|
|
28
|
+
baseUrl?: string;
|
|
29
|
+
/** 默认 DASHSCOPE_VIDEO_MODEL ?? 'happyhorse-1.1-t2v' */
|
|
30
|
+
model?: string;
|
|
31
|
+
}
|
|
32
|
+
export declare const DEFAULT_IMAGE_MODEL = "z-image-turbo";
|
|
33
|
+
export declare const DEFAULT_VIDEO_MODEL = "happyhorse-1.1-t2v";
|
|
34
|
+
export interface ImageGenClient {
|
|
35
|
+
generateImage(req: ImageGenRequest, options?: {
|
|
36
|
+
signal?: AbortSignal;
|
|
37
|
+
}): Promise<ImageGenResult>;
|
|
38
|
+
}
|
|
39
|
+
export interface VideoGenClient {
|
|
40
|
+
createVideoTask(req: VideoGenRequest, options?: {
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
taskId: string;
|
|
44
|
+
}>;
|
|
45
|
+
videoStatus(taskId: string, options?: {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
}): Promise<VideoGenStatus>;
|
|
48
|
+
}
|
|
49
|
+
/** 图片生成客户端(独立配置——不同端点/键/模型) */
|
|
50
|
+
export declare function createDashscopeImage(opts?: ImageGenOptions): ImageGenClient;
|
|
51
|
+
/** 视频任务客户端(独立配置) */
|
|
52
|
+
export declare function createDashscopeVideo(opts?: VideoGenOptions): VideoGenClient;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu AI — OpenAi provider 构造(new OpenAi() / OpenAi() ——同 ai() 返回模块)
|
|
3
|
+
*
|
|
4
|
+
* 参考 openai 兼容实现(client.ts——Chat/Agent 引擎)+ 多模态(multimodal.ts)——
|
|
5
|
+
* env 读取(DEEPSEEK_*)与模块组装(assemble)在这里汇合:
|
|
6
|
+
* new OpenAi(opts) → AiClientModule(app.use 注入 ctx.ai——全能力)
|
|
7
|
+
* ai() 工厂的默认分支 = OpenAi(provider 选择器——正门构造对称 MemoryAi)。
|
|
8
|
+
*/
|
|
9
|
+
import { type AiClientOptions } from './client.ts';
|
|
10
|
+
import { type AiClientModule } from './assemble.ts';
|
|
11
|
+
/** OpenAi 构造选项(同 AiClientOptions——见 client.ts) */
|
|
12
|
+
export type OpenAiOptions = AiClientOptions;
|
|
13
|
+
export interface OpenAi {
|
|
14
|
+
new (options?: OpenAiOptions): OpenAi;
|
|
15
|
+
}
|
|
16
|
+
export declare function OpenAi(options?: OpenAiOptions): AiClientModule;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/db — bodyOf(shape → body 校验——handler 样板消失)
|
|
3
|
+
*
|
|
4
|
+
* 开发者动线(W0 体验提升):shape 已知全部字段——handler 的 body 不再
|
|
5
|
+
* 手写类型/必填/枚举校验。parseBody 复用 insertSchema/updateSchema 变体
|
|
6
|
+
* (auto 列省略 · nullable/default 可缺省 · enum 校验)——与 orm 单源。
|
|
7
|
+
*
|
|
8
|
+
* 用法(手写 route——与 gql/rest 协议面同源):
|
|
9
|
+
* const body = await bodyOf(req, agents) // BodyOf<typeof agents>
|
|
10
|
+
* const patch = await bodyOf(req, agents, { variant: 'patch' }) // PatchOf
|
|
11
|
+
*
|
|
12
|
+
* 错误语义:ValidationError(400 面——错误消息含字段路径/期望——errorOf
|
|
13
|
+
* 映射;校验失败不抛原始 ZodError 噪音——可读优先)。
|
|
14
|
+
*/
|
|
15
|
+
import type { ZodRawShape } from '../../shared/zod.ts';
|
|
16
|
+
import type { Shape, BodyOf } from './shape.ts';
|
|
17
|
+
export interface BodyOfOptions {
|
|
18
|
+
/** insert(缺省——裸行 body——省略 auto)· patch(全可选——部分更新) */
|
|
19
|
+
variant?: 'insert' | 'patch';
|
|
20
|
+
/** 系统列(租户/服务端注入面)——校验前剔除(不变式:注入列声明面权威——
|
|
21
|
+
* body 传该键被忽略而非校验——W4 试点(agents app_id)实证) */
|
|
22
|
+
omit?: string[];
|
|
23
|
+
}
|
|
24
|
+
type ShapeLike<S extends ZodRawShape> = Shape<S> | {
|
|
25
|
+
__shape: import('./shape.ts').Shape<S>;
|
|
26
|
+
};
|
|
27
|
+
/** 请求体 → 类型化输入行(shape 变体校验——enum/必填/nullable/auto 省略)。
|
|
28
|
+
* 命名纪律:parseBody(request.ts)是通用 JSON 解析——bodyOf 是 shape 校验面(一个词一个概念) */
|
|
29
|
+
export declare function bodyOf<S extends ZodRawShape>(req: Request, shapeDef: ShapeLike<S>, opts?: BodyOfOptions): Promise<BodyOf<S>>;
|
|
30
|
+
/** body 输入行类型快捷(parseBody 返回面——语义对等导出) */
|
|
31
|
+
export type { BodyOf, PatchOf } from './shape.ts';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ConsistencyIssue {
|
|
2
|
+
level: 'error' | 'warn';
|
|
3
|
+
kind: string;
|
|
4
|
+
table: string;
|
|
5
|
+
column?: string;
|
|
6
|
+
expected?: string;
|
|
7
|
+
found?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface DeclaredTable {
|
|
10
|
+
name: string;
|
|
11
|
+
fields: Record<string, unknown>;
|
|
12
|
+
dbFields: Record<string, {
|
|
13
|
+
column?: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export interface LiveTable {
|
|
17
|
+
name: string;
|
|
18
|
+
columns: {
|
|
19
|
+
name: string;
|
|
20
|
+
type: string;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
/** PG 类型名归一(宽等价组——声明 DDL 名 vs 库 data_type 对齐;组内不误报) */
|
|
24
|
+
export declare function normalizeType(t: string): string;
|
|
25
|
+
export declare function diffConsistency(decl: DeclaredTable[], live: LiveTable[]): {
|
|
26
|
+
ok: boolean;
|
|
27
|
+
issues: ConsistencyIssue[];
|
|
28
|
+
};
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* weifuwu/db — 自研数据库引擎契约层(接口与实现分离)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 自研引擎(src/db/postgres|redis 的 class)实现它们:
|
|
4
|
+
* 三个接口族:消费方只依赖接口类型,自研引擎(src/db/postgres|redis 的 class)实现:
|
|
6
5
|
*
|
|
7
6
|
* PoolConnection 通用连接(pg/redis 池中连接项:生命周期 + 健康)
|
|
8
7
|
* ├─ PostgresPoolConnection 特化:参数化查询(PgConnection 实现)
|
|
9
8
|
* └─ RedisPoolConnection 特化:命令执行(RedisClient 实现)
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Redis(+Pipeline/Subscriber) Redis 命令面(ctx.redis)——命令面封闭无 parser
|
|
10
|
+
* DbAdapter / Orm ORM AST 协议层(业务唯一数据入口——ctx.orm)
|
|
12
11
|
*
|
|
13
12
|
* 变更纪律( 协议层):改契约须 TDD 先行 + 真库验证(CS-04/CS-05)。
|
|
14
13
|
*/
|
|
@@ -54,29 +53,6 @@ export interface QueryResult<T = Row> extends Array<T> {
|
|
|
54
53
|
export interface PostgresPoolConnection extends PoolConnection {
|
|
55
54
|
query(sql: string, params?: unknown[]): Promise<QueryResult>;
|
|
56
55
|
}
|
|
57
|
-
/**
|
|
58
|
-
* SQL 标签模板(ctx.sql):`sql\`SELECT * FROM t WHERE id = ${id}\`` + 方法面。
|
|
59
|
-
* 事务能力走中间件面 `pg.transaction`(PostgresClient)——不在 Sql 接口。
|
|
60
|
-
*
|
|
61
|
-
* 三条执行路径(同一契约双实现):
|
|
62
|
-
* 标签模板 / unsafe —— 原生 SQL 字符串(Postgres 生态面、DDL、复杂原生查询)
|
|
63
|
-
* query —— Query Language(结构化对象 → 真库编译 SQL / 内存直执行 AST)
|
|
64
|
-
*/
|
|
65
|
-
export interface Sql {
|
|
66
|
-
(strings: TemplateStringsArray, ...values: unknown[]): Promise<Row[]>;
|
|
67
|
-
/** 原生 SQL(DDL / 动态表名);$1 占位符 + 参数 */
|
|
68
|
-
unsafe(sql: string, params?: unknown[]): Promise<Row[]>;
|
|
69
|
-
/** Query Language 入口:`sql.query.from('users').where({...}).run()` */
|
|
70
|
-
query: import('../db/query.ts').QueryBuilder;
|
|
71
|
-
/** raw 逃生舱:`sql.raw\`NOW() - interval '7 days'\``——真库透传/内存裁剪 */
|
|
72
|
-
raw(strings: TemplateStringsArray, ...values: unknown[]): import('../db/query.ts').RawSql;
|
|
73
|
-
/** PG 数组参数:`ANY(\${sql.array(ids)}::uuid[])`——默认数组插值是 jsonb 语义
|
|
74
|
-
* (object → JSON),PG 数组语义需显式标记(两义并存零破坏——2027-10 批量审批实证) */
|
|
75
|
-
array(values: unknown[]): {
|
|
76
|
-
__pgArray: unknown[];
|
|
77
|
-
};
|
|
78
|
-
close(): Promise<void>;
|
|
79
|
-
}
|
|
80
56
|
/** Redis 连接(PoolConnection 特化:命令执行) */
|
|
81
57
|
export interface RedisPoolConnection extends PoolConnection {
|
|
82
58
|
command(name: string, ...args: (string | number)[]): Promise<RespValue>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* filterToWhere —— filter 对象 → WhereExpr 共享转换(命名契约 W0)
|
|
3
|
+
*
|
|
4
|
+
* 协议面(gql filter 输入 / rest query 参数)的数据面声明式过滤 → 查询 AST
|
|
5
|
+
* 的 WhereExpr——**一处实现三面用**(gql/rest/typedQuery 数据面语义一致)。
|
|
6
|
+
*
|
|
7
|
+
* 契约(与 query.ts WhereExpr 对齐):
|
|
8
|
+
* - 字段名 → 列名映射(shapeDef.dbFields[field].column)
|
|
9
|
+
* - and/or 递归组({ and: [...], or: [...] })
|
|
10
|
+
* - 算子集:eq/ne/gt/gte/lt/lte/in/notIn/isNull + contains/startsWith/endsWith
|
|
11
|
+
* (→ ilike 转义——% _ 反斜杠转义)
|
|
12
|
+
* - 单 eq 特判({ col: { eq: v } } 直接 { col: { eq: v } }——组合式 path)
|
|
13
|
+
* - undefined 值显式拒绝(W2 定案——不静默跳过——省略键或显式 isNull)
|
|
14
|
+
* - 租户注入是调用侧拼装(协议策略——不在此函数内)
|
|
15
|
+
*/
|
|
16
|
+
import type { Shape } from './shape.ts';
|
|
17
|
+
/** 列映射面(shapeDef.dbFields——字段→DB 列) */
|
|
18
|
+
export interface FilterShapeFields {
|
|
19
|
+
dbFields: Record<string, {
|
|
20
|
+
column?: string;
|
|
21
|
+
}>;
|
|
22
|
+
}
|
|
23
|
+
/** filter 对象 → WhereExpr(字段→列名映射 + 算子转译 + 组合递归) */
|
|
24
|
+
export declare function filterToWhere(filter: Record<string, unknown> | null | undefined, shapeDef: Pick<Shape<Record<string, never>>, 'dbFields'> | FilterShapeFields): Record<string, unknown>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/gql —— gqlFromShape:shape → GraphQL 生成器(纯函数)
|
|
3
|
+
*
|
|
4
|
+
* shape(数据"是什么")→ SDL 字符串 + resolver 桥(filter 参数 → WhereExpr 算子)
|
|
5
|
+
* 输出即内置接口输入(graphql() 的 schema/resolvers——makeExecutableSchema 链路)
|
|
6
|
+
*
|
|
7
|
+
* 生成面(W6 首版·诚实边界见 plan 判负记录):
|
|
8
|
+
* - Query: list(filter/sort/limit/offset) · one(filter)
|
|
9
|
+
* - Mutation: insert(data) · update(id,patch) · delete(id)
|
|
10
|
+
* - 类型:string/uuid→String·number→Float·boolean→Boolean·date→String(ISO)·
|
|
11
|
+
* enum/literal→GraphQL enum·array→[T!]·optional→可空
|
|
12
|
+
* - Filter:每字段输入对象(eq/ne/gt/gte/lt/lte/in/notIn/isNull/contains/ilike/
|
|
13
|
+
* startsWith/endsWith——按列类型裁剪)+ and/or 组合
|
|
14
|
+
* - Sort:[{ field: enum!, dir: enum }]
|
|
15
|
+
* - 租户 scope:tenant 配置自动注入 where/insert(上下文 appId)
|
|
16
|
+
* 判负(后续再议):关系面(JOIN/嵌套对象——非 W6)·json 字段(String 序列化)·
|
|
17
|
+
* 复杂 mutation(批量/upsert/事务)·uuid→ID 映射(String 面)
|
|
18
|
+
*/
|
|
19
|
+
import { type Shape } from './shape.ts';
|
|
20
|
+
import { type ZodRawShape } from '../../shared/zod.ts';
|
|
21
|
+
export interface GqlShapeOptions {
|
|
22
|
+
/** 生成类型名(默认表名 PascalCase) */
|
|
23
|
+
name?: string;
|
|
24
|
+
/** 执行面取数(默认 ctx.orm——协议层 = AST;orm.gql 内部绑定 ormBase) */
|
|
25
|
+
sql?: (ctx: unknown) => unknown;
|
|
26
|
+
/** 租户 scope:字段名 + 上下文取值(自动注入 where/insert——跨租户隔离;
|
|
27
|
+
* 与 OrmTenant.value 同签名——undefined=无值(不注入) */
|
|
28
|
+
tenant?: {
|
|
29
|
+
field: string;
|
|
30
|
+
value: (ctx: unknown) => string | undefined;
|
|
31
|
+
};
|
|
32
|
+
/** 默认分页上限(默认 100) */
|
|
33
|
+
maxLimit?: number;
|
|
34
|
+
/** 字段策略(命名契约 W0——fieldPolicy 首版):敏感列豁免——
|
|
35
|
+
* SDL 不生成(字段/Filter/Sort/Insert/Patch 全不出现)+ resolver 不返回 */
|
|
36
|
+
hidden?: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface GqlShapeOutput {
|
|
39
|
+
typeDefs: string;
|
|
40
|
+
resolvers: Record<string, Record<string, (...args: any[]) => any>>;
|
|
41
|
+
}
|
|
42
|
+
export declare function gqlFromShape<S extends ZodRawShape>(shapeDef: Shape<S>, opts?: GqlShapeOptions): GqlShapeOutput;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/db — http(协议面 helpers——handler 样板消失第二刀)
|
|
3
|
+
*
|
|
4
|
+
* listQuery:URL query → { filter, sort, limit, offset }(rest 私有解析提取——
|
|
5
|
+
* 手写 route 的 32 处 searchParams 解析收口)——枚举白名单/sort 字段校验/
|
|
6
|
+
* limit clamp(默认 20 · max 100)与 rest 行为等价。
|
|
7
|
+
* errorResponse:错误 → Response(状态码映射——DbError validation→400 ·
|
|
8
|
+
* 唯一冲突 23505→409 · 显式 status 优先(业务守卫 403 等))——catch 样板收口。
|
|
9
|
+
*/
|
|
10
|
+
import type { ZodRawShape } from '../../shared/zod.ts';
|
|
11
|
+
import type { Shape } from './shape.ts';
|
|
12
|
+
export interface ListQueryOptions {
|
|
13
|
+
/** limit 上限(缺省 100) */
|
|
14
|
+
maxLimit?: number;
|
|
15
|
+
/** limit 缺省(缺省 20) */
|
|
16
|
+
defaultLimit?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* URL query → 列表参数(eq 直排 · sort `-field,field2` 多字段 · limit/offset clamp)。
|
|
20
|
+
*
|
|
21
|
+
* 校验失败(枚举值白名单/未知 sort 字段)→ 抛错(调用方 errorResponse——400)。
|
|
22
|
+
* filter 键 = shape 字段名(未知列由 orm 面校验兜底——42P01 显式)。
|
|
23
|
+
*/
|
|
24
|
+
export declare function listQuery(url: URL, shapeDef: Shape<ZodRawShape>, opts?: ListQueryOptions): {
|
|
25
|
+
filter: Record<string, unknown>;
|
|
26
|
+
sort: {
|
|
27
|
+
field: string;
|
|
28
|
+
dir: 'asc' | 'desc';
|
|
29
|
+
}[];
|
|
30
|
+
limit: number;
|
|
31
|
+
offset: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* 错误 → Response(状态码映射——catch 样板收口)。
|
|
35
|
+
* - 显式 status 优先(业务守卫抛错 403 等——调用方定语义)
|
|
36
|
+
* - DbError:validation → 400 · 23505 唯一冲突 → 409 · 其余 → 400(缺省)
|
|
37
|
+
*/
|
|
38
|
+
export declare function errorResponse(e: unknown, status?: number): Response;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Row, QueryResult } from './contracts.ts';
|
|
2
2
|
import type { Query } from './query.ts';
|
|
3
3
|
/** 事务快照表条目(rows + 元数据副本——restore 需复活事务内 DROP 掉的表) */
|
|
4
4
|
export interface MemorySnapshotEntry {
|
|
5
|
+
state: 'declared' | 'observed';
|
|
5
6
|
rows: Row[];
|
|
6
7
|
nextId: number;
|
|
7
8
|
columns: string[];
|
|
@@ -11,26 +12,71 @@ export interface MemorySnapshotEntry {
|
|
|
11
12
|
defaultUuid: boolean;
|
|
12
13
|
};
|
|
13
14
|
uniques: string[];
|
|
15
|
+
groups: string[][];
|
|
14
16
|
defaultNow: string[];
|
|
17
|
+
defaultVals: Record<string, unknown>;
|
|
15
18
|
}
|
|
16
19
|
export type MemorySnapshot = Map<string, MemorySnapshotEntry>;
|
|
17
20
|
export declare class MemorySql {
|
|
21
|
+
/** 客户端路径列校验开关(wire 服务器端关闭——它是 PG 替身:列错由真库语义 42703 报) */
|
|
22
|
+
private opts;
|
|
23
|
+
constructor(opts?: {
|
|
24
|
+
validateCols?: boolean;
|
|
25
|
+
});
|
|
18
26
|
private tables;
|
|
19
|
-
/**
|
|
20
|
-
private
|
|
21
|
-
/** 标签模板 → 参数化 SQL(values 顺序即 $1..$n
|
|
22
|
-
tag(strings: TemplateStringsArray, values: unknown[]): Promise<Row[]>;
|
|
23
|
-
unsafe(sql: string, params?: unknown[]): Promise<Row[]>;
|
|
27
|
+
/** CREATE TYPE AS ENUM 注册(幂等——DO 块 EXCEPTION duplicate_object 语义) */
|
|
28
|
+
private enums;
|
|
29
|
+
/** 标签模板 → 参数化 SQL(values 顺序即 $1..$n)——W3c:文本面删净——仅 AST 执行 */
|
|
24
30
|
close(): Promise<void>;
|
|
25
31
|
/** 执行结构化查询(真库编译 SQL / 内存直操作表) */
|
|
26
32
|
executeQuery(q: Query): QueryResult<Row>;
|
|
33
|
+
/** jsonb 列读取解码(对齐真库驱动 convertValue(114/3802) → JSON.parse)
|
|
34
|
+
* 状态机行为矩阵(W3):
|
|
35
|
+
* - declared:columnTypes 判定(jsonb 列解码——确定)
|
|
36
|
+
* - observed:行键值启发(JSON 可解析且结果为对象/数组 → 解码——列型未知的
|
|
37
|
+
* 诚实降级;text 列存 '[..]' 字符串会被解码——透明注记在 inspectTable) */
|
|
38
|
+
private jsonDecodeRows;
|
|
39
|
+
/** 合法列集:DDL columns ∪ 观测行键(insert 建表无 DDL——行键即事实列) */
|
|
40
|
+
private tableCols;
|
|
41
|
+
/** W1 列校验:where/join-on/投影/orderBy/groupBy 纯列引用 ∈ 表列集(未知列不再静默) */
|
|
42
|
+
private assertKnownCols;
|
|
27
43
|
private execSelect;
|
|
28
44
|
private execInsert;
|
|
29
45
|
private execUpdate;
|
|
30
46
|
private execDelete;
|
|
47
|
+
private assertTableExists;
|
|
48
|
+
/** 状态机获取:absent 访问显式拒绝(42P01——对齐真库——join 未注册表不再静默空表) */
|
|
31
49
|
private table;
|
|
50
|
+
/** 状态机唯一创建点:absent → 空表(state 由调用方转换——declare 或 observe) */
|
|
51
|
+
private obtain;
|
|
52
|
+
/** 状态机转换:declared(声明态——applySchema/executeDdl(createTable) 调用) */
|
|
53
|
+
private toDeclared;
|
|
32
54
|
/** 表是否存在(PG 服务器 42P01 检查——内存惰性建表 vs 真库报错) */
|
|
33
55
|
hasTable(table: string): boolean;
|
|
56
|
+
/** 状态可见面(W3 状态机——透明契约):状态 + 列集 + 类型 + 约束快照——测试断言用 */
|
|
57
|
+
inspectTable(table: string): {
|
|
58
|
+
state: 'declared' | 'observed';
|
|
59
|
+
columns: string[];
|
|
60
|
+
columnTypes: Record<string, string>;
|
|
61
|
+
constraints: {
|
|
62
|
+
pk?: {
|
|
63
|
+
col: string;
|
|
64
|
+
defaultUuid: boolean;
|
|
65
|
+
};
|
|
66
|
+
uniques: string[];
|
|
67
|
+
groups: string[][];
|
|
68
|
+
defaultNow: string[];
|
|
69
|
+
defaultVals: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
/** 全表快照(W3 一致性诊断——schemaSnapshot:表/列/类型——透明面) */
|
|
73
|
+
schemaSnapshot(): {
|
|
74
|
+
name: string;
|
|
75
|
+
columns: {
|
|
76
|
+
name: string;
|
|
77
|
+
type: string;
|
|
78
|
+
}[];
|
|
79
|
+
}[];
|
|
34
80
|
/** PG 服务器 Describe:列类型 → OID 推断辅助 */
|
|
35
81
|
getColumnType(table: string, col: string): string | undefined;
|
|
36
82
|
/** PG 服务器 Parse:INSERT VALUES 列序 → 类型列表 */
|
|
@@ -39,8 +85,20 @@ export declare class MemorySql {
|
|
|
39
85
|
snapshot(): MemorySnapshot;
|
|
40
86
|
/** 恢复快照(ROLLBACK)——全量还原(含复活事务内 DROP 掉的表);快照后新建的表清空 */
|
|
41
87
|
restore(snap: MemorySnapshot): void;
|
|
88
|
+
/** 声明式 Schema 应用(applySchema——SchemaModule → 元数据直构造;与 DDL 解析器同落点) */
|
|
89
|
+
applySchema(mod: import('./schema.ts').SchemaModule): void;
|
|
42
90
|
/** DDL 执行(parser 产出 DdlQuery)——约束提取到表元数据 */
|
|
43
91
|
private executeDdl;
|
|
44
92
|
}
|
|
45
|
-
/**
|
|
46
|
-
export declare function
|
|
93
|
+
/** 余弦相似度(pgvector `1 - (a <=> b)` 等价——cosine distance 变体) */
|
|
94
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
95
|
+
export declare function resolveExprValue(_col: string, cur: unknown, expr: unknown, row: Record<string, unknown>): unknown;
|
|
96
|
+
export declare function isMergeExpr(v: unknown): boolean;
|
|
97
|
+
/** 日期表达式值求值(where 值面:__interval/__monthStart——编码即语义) */
|
|
98
|
+
export declare function dateExprValue(v: unknown): unknown;
|
|
99
|
+
/** 内存 ORM(测试装配——orm 面直执行;close 释放) */
|
|
100
|
+
export declare function createMemoryOrm(engine?: MemorySql): {
|
|
101
|
+
orm: import('./orm.ts').Orm;
|
|
102
|
+
mem: MemorySql;
|
|
103
|
+
close: () => Promise<void>;
|
|
104
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* weifuwu/ops —— operator 契约(shape+operator 架构的查询行为层)
|
|
3
|
+
*
|
|
4
|
+
* 算子(drizzle 式)→ WhereExpr(MemorySql 已验证执行面——零新执行代码)
|
|
5
|
+
* 类型收窄:ColRef<T> phantom——eq 值类型绑定列类型·ilike 仅 string 列(编译期)
|
|
6
|
+
*
|
|
7
|
+
* 用法:
|
|
8
|
+
* const agents = cols('agents', { id: z.uuid(), type: z.enum(['ai','user']), name: z.string() })
|
|
9
|
+
* where(and(eq(agents.type, 'ai'), ilike(agents.name, '%张%')))
|
|
10
|
+
* → { type: 'ai', name: { ilike: '%张%' } }(and 为顶层 AND 合并——单列同键覆盖场景除外)
|
|
11
|
+
*/
|
|
12
|
+
import type { WhereExpr } from './query.ts';
|
|
13
|
+
/** 列引用(phantom:输出类型 T 绑定列类型——算子值收窄) */
|
|
14
|
+
export interface ColRef<T = unknown> {
|
|
15
|
+
/** 列名(dsl 引用名——通常即字段名/别名.字段名) */
|
|
16
|
+
readonly ref: string;
|
|
17
|
+
/** 输出类型 phantom */
|
|
18
|
+
readonly __out: T;
|
|
19
|
+
}
|
|
20
|
+
/** 形状驱动的列引用表(keys 与 shape 字段一致——类型面) */
|
|
21
|
+
export type ShapeCols<S extends Record<string, unknown>> = {
|
|
22
|
+
[K in keyof S]: ColRef<S[K]>;
|
|
23
|
+
};
|
|
24
|
+
/** 从字段定义构建列引用(形状驱动——类型从 shape 类型参数推导) */
|
|
25
|
+
export declare function cols<S extends Record<string, unknown>>(_prefix: string, _shape?: S): ShapeCols<S>;
|
|
26
|
+
/** 等值算子(算子模式唯一形态:`{ [col]: { eq: value } }`——裸标量形态已移除) */
|
|
27
|
+
export declare const eq: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
28
|
+
export declare const ne: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
29
|
+
export declare const gt: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
30
|
+
export declare const gte: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
31
|
+
export declare const lt: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
32
|
+
export declare const lte: <T>(col: ColRef<T>, value: T) => WhereExpr;
|
|
33
|
+
export declare const inArray: <T>(col: ColRef<T>, values: T[]) => WhereExpr;
|
|
34
|
+
export declare const notInArray: <T>(col: ColRef<T>, values: T[]) => WhereExpr;
|
|
35
|
+
export declare const between: <T>(col: ColRef<T>, lo: T, hi: T) => WhereExpr;
|
|
36
|
+
export declare const like: (col: ColRef<string>, pattern: string) => WhereExpr;
|
|
37
|
+
export declare const ilike: (col: ColRef<string>, pattern: string) => WhereExpr;
|
|
38
|
+
/** contains(%v%——ILIKE 语义——内部模糊搜索面) */
|
|
39
|
+
export declare const contains: (col: ColRef<string>, v: string) => WhereExpr;
|
|
40
|
+
export declare const startsWith: (col: ColRef<string>, v: string) => WhereExpr;
|
|
41
|
+
export declare const endsWith: (col: ColRef<string>, v: string) => WhereExpr;
|
|
42
|
+
/** 列对列等式(join on 面:`eqCol(dm.departmentId, d.id)` → `{ 'dm.department_id': { col: 'd.id' } }`) */
|
|
43
|
+
export declare const eqCol: (left: ColRef<unknown>, right: ColRef<unknown>) => WhereExpr;
|
|
44
|
+
export declare const isNull: (col: ColRef<unknown>) => WhereExpr;
|
|
45
|
+
export declare const isNotNull: (col: ColRef<unknown>) => WhereExpr;
|
|
46
|
+
/** NOW()(时间戳 SET——`col = NOW()`) */
|
|
47
|
+
export declare const now: () => unknown;
|
|
48
|
+
/** NOW() + INTERVAL 'n unit'(n 负 = 过去——`NOW() - INTERVAL 'n unit'`) */
|
|
49
|
+
export declare function nowInterval(n: number, unit?: 'day' | 'hour' | 'minute'): unknown;
|
|
50
|
+
/** NOW() - INTERVAL 'n unit'(时间窗查询——记忆/审计等) */
|
|
51
|
+
export declare function nowAgo(n: number, unit?: 'day' | 'hour' | 'minute'): unknown;
|
|
52
|
+
/** DATE_TRUNC('month', NOW())(月起始——计量/账单窗口) */
|
|
53
|
+
export declare const monthStart: () => unknown;
|
|
54
|
+
/** 列引用 SET(`col = other_col`——messages.content = ai_draft 等) */
|
|
55
|
+
export declare const colRef: (name: string) => unknown;
|
|
56
|
+
/**
|
|
57
|
+
* AND 组合(顶层列合并——同键(eq 两次)后者覆盖的边界:显式传入 and 数组时
|
|
58
|
+
* 以数组语义(逐条)执行——见 MemorySql 'and' 分支)
|
|
59
|
+
*/
|
|
60
|
+
/** 条件安全组合:空对象/联合条件(`q ? {...} : {}` 样板)直接收——空对象恒真(AND 无约束/OR 恒真符合直觉) */
|
|
61
|
+
export type CondWhere = WhereExpr | Record<string, never>;
|
|
62
|
+
export declare function and(...conds: CondWhere[]): WhereExpr;
|
|
63
|
+
export declare function or(...conds: CondWhere[]): WhereExpr;
|
|
64
|
+
export declare function not(cond: WhereExpr): WhereExpr;
|
|
65
|
+
/** jsonb 数组追加(`col = col || $n::jsonb`)——agent_run_states.steps 等 */
|
|
66
|
+
export declare function mergeAppend(val: unknown): unknown;
|
|
67
|
+
/** 数值自增(`col = col + n`)——answer_cache.hits 等 */
|
|
68
|
+
export declare function mergeInc(n?: number): unknown;
|
|
69
|
+
/** 时间戳(`NOW()`)——updated_at 等(与 ops.now 同编码) */
|
|
70
|
+
export declare const mergeNow: () => unknown;
|