@deepexi/datasense-connector 3.0.1 → 3.1.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 +158 -139
- package/package.json +19 -28
- package/scripts/build.ts +188 -0
- package/src/define.ts +267 -0
- package/src/descriptor.ts +116 -0
- package/src/errors.ts +105 -0
- package/src/index.ts +108 -0
- package/src/internal/location.ts +23 -0
- package/src/runtime/guest/bridge.ts +238 -0
- package/src/runtime/guest/cache.ts +43 -0
- package/src/runtime/guest/check.ts +17 -0
- package/src/runtime/guest/crypto.ts +166 -0
- package/src/runtime/guest/ctx.ts +157 -0
- package/src/runtime/guest/db.ts +59 -0
- package/src/runtime/guest/failure.ts +69 -0
- package/src/runtime/guest/http.ts +194 -0
- package/src/runtime/guest/index.ts +102 -0
- package/{runtime/guest/limits.d.ts → src/runtime/guest/limits.ts} +12 -12
- package/src/runtime/guest/loader.ts +210 -0
- package/src/runtime/guest/log.ts +47 -0
- package/src/runtime/guest/map.ts +45 -0
- package/src/runtime/guest/operation.ts +193 -0
- package/src/runtime/guest/paginate.ts +169 -0
- package/src/runtime/guest/pull.ts +177 -0
- package/src/runtime/guest/push.ts +92 -0
- package/src/runtime/guest/signal.ts +14 -0
- package/src/runtime/guest/suggest.ts +51 -0
- package/src/runtime/guest/time.ts +137 -0
- package/src/runtime/guest-runtime.ts +75 -0
- package/src/runtime/index.ts +53 -0
- package/src/runtime/protocol.ts +557 -0
- package/src/runtime/session.ts +216 -0
- package/src/testing/child.ts +21 -0
- package/src/testing/compliance.ts +343 -0
- package/src/testing/engine.ts +445 -0
- package/src/testing/fixtures.ts +591 -0
- package/src/testing/gateway.ts +482 -0
- package/src/testing/import-guard.ts +221 -0
- package/src/testing/index.ts +43 -0
- package/src/testing/local-db.ts +226 -0
- package/src/testing/mock-external-system.ts +249 -0
- package/src/testing/pinned-http.ts +144 -0
- package/src/testing/recorder.ts +140 -0
- package/src/testing/redaction.ts +94 -0
- package/src/testing/replay.ts +437 -0
- package/src/testing/run-tests.ts +115 -0
- package/src/testing/schema.ts +70 -0
- package/src/testing/source-loader.ts +374 -0
- package/src/testing/types.ts +78 -0
- package/src/types.ts +329 -0
- package/src/validate.ts +267 -0
- package/test/build.test.ts +159 -0
- package/test/define.test-d.ts +182 -0
- package/test/fixtures/acceptance.ts +156 -0
- package/test/fixtures/connectors/http-pull/.ontos/descriptor.json +72 -0
- package/test/fixtures/connectors/http-pull/.ontos/types.ts +61 -0
- package/test/fixtures/connectors/http-pull/package.json +5 -0
- package/test/fixtures/connectors/http-pull/streams/items/index.ts +37 -0
- package/test/fixtures/connectors/http-pull/streams/items/map.ts +12 -0
- package/test/fixtures/connectors/http-pull/streams/items/tests/basic/case.json +15 -0
- package/test/fixtures/connectors/http-pull/streams/items/tests/basic/exchanges.ndjson +2 -0
- package/test/fixtures/connectors/pg-pull/.ontos/descriptor.json +151 -0
- package/test/fixtures/connectors/pg-pull/.ontos/types.ts +62 -0
- package/test/fixtures/connectors/pg-pull/lib/sql.ts +14 -0
- package/test/fixtures/connectors/pg-pull/package.json +5 -0
- package/test/fixtures/connectors/pg-pull/streams/customers/index.ts +30 -0
- package/test/fixtures/connectors/pg-pull/streams/customers/tests/customers-full/case.json +15 -0
- package/test/fixtures/connectors/pg-pull/streams/customers/tests/customers-full/exchanges.ndjson +3 -0
- package/test/fixtures/connectors/pg-pull/streams/orders/index.ts +32 -0
- package/test/fixtures/descriptor.ts +54 -0
- package/test/fixtures/kingdee-example.ts +82 -0
- package/test/fixtures/record-acceptance.ts +32 -0
- package/test/runtime/ctx.test.ts +434 -0
- package/test/runtime/helpers.ts +157 -0
- package/test/runtime/jobs.test.ts +444 -0
- package/test/runtime/operation.test.ts +175 -0
- package/test/runtime/session.test.ts +229 -0
- package/test/testing/acceptance-fixtures.test.ts +69 -0
- package/test/testing/compliance.test.ts +247 -0
- package/test/testing/engine.test.ts +283 -0
- package/test/testing/fixtures.test.ts +221 -0
- package/test/testing/gateway.test.ts +337 -0
- package/test/testing/import-guard.test.ts +45 -0
- package/test/testing/mock-external-system.test.ts +144 -0
- package/test/testing/operation-fixtures.test.ts +160 -0
- package/test/testing/recorder.test.ts +163 -0
- package/test/testing/redaction.test.ts +54 -0
- package/test/testing/replay.test.ts +207 -0
- package/test/testing/run-tests.test.ts +137 -0
- package/test/testing/source-loader.test.ts +220 -0
- package/test/validate-config.test.ts +104 -0
- package/tsconfig.build.json +23 -0
- package/tsconfig.json +19 -0
- package/cjs/index.cjs +0 -1015
- package/cjs/runtime.cjs +0 -752
- package/cjs/testing.cjs +0 -3591
- package/errors.d.ts +0 -17
- package/errors.js +0 -53
- package/guest.cjs +0 -2659
- package/index.d.ts +0 -13
- package/index.js +0 -7
- package/internal/location.d.ts +0 -6
- package/internal/location.js +0 -8
- package/presentation.d.ts +0 -38
- package/presentation.js +0 -268
- package/runtime/guest/bridge.d.ts +0 -53
- package/runtime/guest/bridge.js +0 -187
- package/runtime/guest/cache.d.ts +0 -3
- package/runtime/guest/cache.js +0 -42
- package/runtime/guest/crypto.d.ts +0 -13
- package/runtime/guest/crypto.js +0 -177
- package/runtime/guest/ctx.d.ts +0 -30
- package/runtime/guest/ctx.js +0 -124
- package/runtime/guest/db.d.ts +0 -6
- package/runtime/guest/db.js +0 -59
- package/runtime/guest/discover.d.ts +0 -29
- package/runtime/guest/discover.js +0 -51
- package/runtime/guest/failure.d.ts +0 -24
- package/runtime/guest/failure.js +0 -63
- package/runtime/guest/http.d.ts +0 -4
- package/runtime/guest/http.js +0 -204
- package/runtime/guest/index.d.ts +0 -12
- package/runtime/guest/index.js +0 -89
- package/runtime/guest/limits.js +0 -12
- package/runtime/guest/loader.d.ts +0 -15
- package/runtime/guest/loader.js +0 -42
- package/runtime/guest/log.d.ts +0 -10
- package/runtime/guest/log.js +0 -36
- package/runtime/guest/map.d.ts +0 -4
- package/runtime/guest/map.js +0 -45
- package/runtime/guest/paginate.d.ts +0 -6
- package/runtime/guest/paginate.js +0 -180
- package/runtime/guest/pull.d.ts +0 -12
- package/runtime/guest/pull.js +0 -150
- package/runtime/guest/push.d.ts +0 -18
- package/runtime/guest/push.js +0 -80
- package/runtime/guest/signal.d.ts +0 -3
- package/runtime/guest/signal.js +0 -12
- package/runtime/guest/time.d.ts +0 -5
- package/runtime/guest/time.js +0 -127
- package/runtime/guest-runtime.d.ts +0 -7
- package/runtime/guest-runtime.js +0 -51
- package/runtime/index.d.ts +0 -18
- package/runtime/index.js +0 -3
- package/runtime/protocol.d.ts +0 -276
- package/runtime/protocol.js +0 -409
- package/runtime/session.d.ts +0 -12
- package/runtime/session.js +0 -191
- package/t.d.ts +0 -18
- package/t.js +0 -26
- package/testing/child.cjs +0 -350
- package/testing/child.d.ts +0 -1
- package/testing/child.js +0 -12
- package/testing/compliance.d.ts +0 -41
- package/testing/compliance.js +0 -291
- package/testing/engine.d.ts +0 -66
- package/testing/engine.js +0 -339
- package/testing/fixtures.d.ts +0 -145
- package/testing/fixtures.js +0 -407
- package/testing/gateway.d.ts +0 -65
- package/testing/gateway.js +0 -402
- package/testing/import-guard.d.ts +0 -57
- package/testing/import-guard.js +0 -187
- package/testing/index.d.ts +0 -33
- package/testing/index.js +0 -10
- package/testing/local-db.d.ts +0 -27
- package/testing/local-db.js +0 -181
- package/testing/pinned-http.d.ts +0 -14
- package/testing/pinned-http.js +0 -125
- package/testing/recorder.d.ts +0 -15
- package/testing/recorder.js +0 -116
- package/testing/redaction.d.ts +0 -28
- package/testing/redaction.js +0 -67
- package/testing/replay.d.ts +0 -50
- package/testing/replay.js +0 -313
- package/testing/schema.d.ts +0 -13
- package/testing/schema.js +0 -65
- package/testing/source-loader.d.ts +0 -19
- package/testing/source-loader.js +0 -238
- package/testing/types.d.ts +0 -79
- package/testing/types.js +0 -18
- package/types.d.ts +0 -302
- package/types.js +0 -13
- package/validate.d.ts +0 -78
- package/validate.js +0 -597
package/src/define.ts
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 编写 API:每个能力目录的 `index.ts` 默认导出一个 `defineStream` / `definePush` / `defineOperation` 的结果,
|
|
3
|
+
* 根目录 `check.ts` 默认导出 `defineCheck` 的结果,数据流目录的 `suggest-columns.ts` 默认导出 `defineSuggestColumns` 的结果。
|
|
4
|
+
*
|
|
5
|
+
* 泛型参数 `D` 是按连接器描述生成的类型(`GeneratedDescriptor` 的形状),由 `ontos admin connector codegen` 生成到
|
|
6
|
+
* `.ontos/types.ts`:那个文件导出已绑定 `D` 的同名函数,作者从它导入,于是表名、列类型、配置项与操作契约都在本地类型检查里核对。
|
|
7
|
+
* 生成文件可以直接写出各项类型,也可以把描述写成 `as const` 字面量后用 `DescriptorTypes<typeof descriptor>` 推出。
|
|
8
|
+
*
|
|
9
|
+
* 运行时这些函数只做最基本的参数检查,返回冻结的普通对象(带 `__ontos` 标记与名字);guest 运行时加载时按连接器描述核对
|
|
10
|
+
* 名字与实现是否一一对应。
|
|
11
|
+
*/
|
|
12
|
+
import type { SuggestedColumn } from './descriptor';
|
|
13
|
+
import type {
|
|
14
|
+
CheckContext, CheckpointItem, LookupResult, OperationContext, OperationHandlers, PullContext, PushContext, PushHandler, PushRequest, RecordItem,
|
|
15
|
+
RemoveItem, StreamFunction, StreamInput, StreamItem,
|
|
16
|
+
} from './types';
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// 生成的类型形状
|
|
20
|
+
|
|
21
|
+
/** 一张表的行类型:主键列必填,其余列可缺省或为 null;可扩展表另带 `[field: string]: unknown`。 */
|
|
22
|
+
export type GeneratedRow = object;
|
|
23
|
+
|
|
24
|
+
export interface GeneratedStream {
|
|
25
|
+
tables: { [table: string]: GeneratedRow };
|
|
26
|
+
/** 数据流参数的值类型(`input.streamConfig`)。 */
|
|
27
|
+
params: object;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface GeneratedPush {
|
|
31
|
+
tables: { [table: string]: GeneratedRow };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GeneratedOperation {
|
|
35
|
+
input: object;
|
|
36
|
+
output: object;
|
|
37
|
+
idempotency: 'supported' | 'unsupported';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 按连接器描述生成的类型(`.ontos/types.ts` 里的 `D`)。各项请写成类型别名(`type X = { … }`),不要写成 `interface`:
|
|
42
|
+
* interface 没有隐式索引签名,赋不给这里的 `{ [name: string]: … }`。
|
|
43
|
+
*/
|
|
44
|
+
export interface GeneratedDescriptor {
|
|
45
|
+
/** 非 secret 配置项的值类型(`ctx.config`);`optional: true` 的项是可选属性。 */
|
|
46
|
+
config: object;
|
|
47
|
+
/** secret 配置项名 → string(`ctx.secrets`,值是凭证句柄或 `exposeToScript` 的明文)。 */
|
|
48
|
+
secrets: object;
|
|
49
|
+
streams: { [name: string]: GeneratedStream };
|
|
50
|
+
/** 含可扩展表的数据流,`tables` 只含可扩展表;没有时为 `{}`(于是 `defineSuggestColumns` 无名可用)。 */
|
|
51
|
+
extensibleStreams: { [name: string]: GeneratedStream };
|
|
52
|
+
pushes: { [name: string]: GeneratedPush };
|
|
53
|
+
operations: { [name: string]: GeneratedOperation };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// 带类型的 ctx
|
|
58
|
+
|
|
59
|
+
type Simplify<T> = { [K in keyof T]: T[K] } & {};
|
|
60
|
+
|
|
61
|
+
/** check、数据流、建议列共用的 ctx 底座:`config` / `secrets` 按描述定型。 */
|
|
62
|
+
export type ConnectorContext<D extends GeneratedDescriptor> = Omit<CheckContext, 'config' | 'secrets'> & {
|
|
63
|
+
readonly config: Readonly<D['config']>;
|
|
64
|
+
readonly secrets: Readonly<D['secrets']>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type StreamTables<D extends GeneratedDescriptor, N extends keyof D['streams']> = D['streams'][N]['tables'];
|
|
68
|
+
type PushTables<D extends GeneratedDescriptor, N extends keyof D['pushes']> = D['pushes'][N]['tables'];
|
|
69
|
+
|
|
70
|
+
export type StreamContext<D extends GeneratedDescriptor, N extends keyof D['streams'] & string> =
|
|
71
|
+
Omit<PullContext, 'config' | 'secrets' | 'record' | 'remove' | 'checkpoint'> & {
|
|
72
|
+
readonly config: Readonly<D['config']>;
|
|
73
|
+
readonly secrets: Readonly<D['secrets']>;
|
|
74
|
+
record<T extends keyof StreamTables<D, N> & string>(table: T, row: StreamTables<D, N>[T]): RecordItem;
|
|
75
|
+
remove<T extends keyof StreamTables<D, N> & string>(table: T, key: Partial<StreamTables<D, N>[T]>): RemoveItem;
|
|
76
|
+
checkpoint(state: unknown): CheckpointItem;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type StreamInputOf<D extends GeneratedDescriptor, N extends keyof D['streams'] & string> =
|
|
80
|
+
Omit<StreamInput, 'streamConfig'> & { streamConfig: Readonly<D['streams'][N]['params']> };
|
|
81
|
+
|
|
82
|
+
export type StreamFn<D extends GeneratedDescriptor, N extends keyof D['streams'] & string> =
|
|
83
|
+
(ctx: StreamContext<D, N>, input: StreamInputOf<D, N>) => AsyncIterable<StreamItem>;
|
|
84
|
+
|
|
85
|
+
export type PushContextOf<D extends GeneratedDescriptor, N extends keyof D['pushes'] & string> = Omit<PushContext, 'config' | 'record' | 'remove'> & {
|
|
86
|
+
readonly config: Readonly<D['config']>;
|
|
87
|
+
record<T extends keyof PushTables<D, N> & string>(table: T, row: PushTables<D, N>[T]): void;
|
|
88
|
+
remove<T extends keyof PushTables<D, N> & string>(table: T, key: Partial<PushTables<D, N>[T]>): void;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export interface PushImpl<D extends GeneratedDescriptor, N extends keyof D['pushes'] & string> {
|
|
92
|
+
verify?(ctx: PushContextOf<D, N>, req: PushRequest): void | Promise<void>;
|
|
93
|
+
map(ctx: PushContextOf<D, N>, req: PushRequest): void | Promise<void>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type OperationContextOf<D extends GeneratedDescriptor> = Omit<OperationContext, 'config' | 'secrets'> & {
|
|
97
|
+
readonly config: Readonly<D['config']>;
|
|
98
|
+
readonly secrets: Readonly<D['secrets']>;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
type OperationInput<D extends GeneratedDescriptor, N extends keyof D['operations']> = D['operations'][N]['input'];
|
|
102
|
+
type OperationOutput<D extends GeneratedDescriptor, N extends keyof D['operations']> = D['operations'][N]['output'];
|
|
103
|
+
|
|
104
|
+
type LookupFn<D extends GeneratedDescriptor, N extends keyof D['operations'] & string> = (
|
|
105
|
+
ctx: OperationContextOf<D>,
|
|
106
|
+
input: { idempotencyKey: string; params: OperationInput<D, N> },
|
|
107
|
+
) => LookupResult<OperationOutput<D, N>> | Promise<LookupResult<OperationOutput<D, N>>>;
|
|
108
|
+
|
|
109
|
+
/** 操作的实现:`idempotency: 'unsupported'` 时必须实现 `lookup`(结果不明时平台据此确认),`supported` 时可选。 */
|
|
110
|
+
export type OperationImpl<D extends GeneratedDescriptor, N extends keyof D['operations'] & string> = {
|
|
111
|
+
run(ctx: OperationContextOf<D>, params: OperationInput<D, N>, meta: { idempotencyKey: string }): OperationOutput<D, N> | Promise<OperationOutput<D, N>>;
|
|
112
|
+
/** 纯函数(拿不到 `ctx`),推演与试运行时代替 `run` 返回模拟输出。 */
|
|
113
|
+
simulate?(params: OperationInput<D, N>): OperationOutput<D, N>;
|
|
114
|
+
} & (D['operations'][N]['idempotency'] extends 'unsupported' ? { lookup: LookupFn<D, N> } : { lookup?: LookupFn<D, N> });
|
|
115
|
+
|
|
116
|
+
export type CheckFn<D extends GeneratedDescriptor> = (ctx: ConnectorContext<D>) => void | Promise<void>;
|
|
117
|
+
|
|
118
|
+
export type SuggestFn<D extends GeneratedDescriptor, N extends keyof D['extensibleStreams'] & string> = (
|
|
119
|
+
ctx: ConnectorContext<D>,
|
|
120
|
+
input: { table: keyof D['extensibleStreams'][N]['tables'] & string },
|
|
121
|
+
) => SuggestedColumn[] | Promise<SuggestedColumn[]>;
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// 运行时的实现对象
|
|
125
|
+
|
|
126
|
+
export interface StreamImpl { readonly __ontos: 'stream'; readonly name: string; readonly run: StreamFunction }
|
|
127
|
+
export interface PushImplBrand { readonly __ontos: 'push'; readonly name: string; readonly handler: PushHandler }
|
|
128
|
+
export interface OperationImplBrand { readonly __ontos: 'operation'; readonly name: string; readonly handlers: OperationHandlers }
|
|
129
|
+
export interface CheckImpl { readonly __ontos: 'check'; readonly run: (ctx: CheckContext) => void | Promise<void> }
|
|
130
|
+
export type SuggestColumnsFunction = (ctx: CheckContext, input: { table: string }) => SuggestedColumn[] | Promise<SuggestedColumn[]>;
|
|
131
|
+
export interface SuggestImpl { readonly __ontos: 'suggest'; readonly name: string; readonly run: SuggestColumnsFunction }
|
|
132
|
+
|
|
133
|
+
function requireName(fn: string, name: unknown): string {
|
|
134
|
+
if (typeof name !== 'string' || name.length === 0) throw new TypeError(`${fn}() needs the capability name as its first argument`);
|
|
135
|
+
return name;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function requireFunction(fn: string, what: string, value: unknown): void {
|
|
139
|
+
if (typeof value !== 'function') throw new TypeError(`${fn}(): ${what} must be a function`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** 数据流实现:`streams/<名>/index.ts` 的默认导出;函数是 async generator,只 `yield` `ctx.record` / `ctx.remove` / `ctx.checkpoint` 的结果。 */
|
|
143
|
+
export function defineStream<D extends GeneratedDescriptor, N extends keyof D['streams'] & string>(name: N, fn: StreamFn<D, N>): StreamImpl {
|
|
144
|
+
requireFunction('defineStream', 'the stream', fn);
|
|
145
|
+
return Object.freeze({ __ontos: 'stream', name: requireName('defineStream', name), run: fn as unknown as StreamFunction });
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** 推送实现:`pushes/<名>/index.ts` 的默认导出;先 `verify`(可选)再 `map`。 */
|
|
149
|
+
export function definePush<D extends GeneratedDescriptor, N extends keyof D['pushes'] & string>(name: N, impl: PushImpl<D, N>): PushImplBrand {
|
|
150
|
+
const checkedName = requireName('definePush', name);
|
|
151
|
+
if (impl === null || typeof impl !== 'object') throw new TypeError('definePush(): the implementation must be an object with map()');
|
|
152
|
+
requireFunction('definePush', 'map', impl.map);
|
|
153
|
+
if (impl.verify !== undefined) requireFunction('definePush', 'verify', impl.verify);
|
|
154
|
+
return Object.freeze({ __ontos: 'push', name: checkedName, handler: impl as unknown as PushHandler });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** 连接器操作实现:`operations/<名>/index.ts` 的默认导出。 */
|
|
158
|
+
export function defineOperation<D extends GeneratedDescriptor, N extends keyof D['operations'] & string>(name: N, impl: OperationImpl<D, N>): OperationImplBrand {
|
|
159
|
+
const checkedName = requireName('defineOperation', name);
|
|
160
|
+
if (impl === null || typeof impl !== 'object') throw new TypeError('defineOperation(): the implementation must be an object with run()');
|
|
161
|
+
const handlers = impl as unknown as Partial<OperationHandlers>;
|
|
162
|
+
requireFunction('defineOperation', 'run', handlers.run);
|
|
163
|
+
if (handlers.lookup !== undefined) requireFunction('defineOperation', 'lookup', handlers.lookup);
|
|
164
|
+
if (handlers.simulate !== undefined) requireFunction('defineOperation', 'simulate', handlers.simulate);
|
|
165
|
+
return Object.freeze({ __ontos: 'operation', name: checkedName, handlers: impl as unknown as OperationHandlers });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** 检查连通:根目录 `check.ts` 的默认导出(有配置项时必须实现)。 */
|
|
169
|
+
export function defineCheck<D extends GeneratedDescriptor>(fn: CheckFn<D>): CheckImpl {
|
|
170
|
+
requireFunction('defineCheck', 'the check', fn);
|
|
171
|
+
return Object.freeze({ __ontos: 'check', run: fn as unknown as CheckImpl['run'] });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** 建议列:`streams/<名>/suggest-columns.ts` 的默认导出,从外部系统读出可扩展表的可用字段。 */
|
|
175
|
+
export function defineSuggestColumns<D extends GeneratedDescriptor, N extends keyof D['extensibleStreams'] & string>(name: N, fn: SuggestFn<D, N>): SuggestImpl {
|
|
176
|
+
requireFunction('defineSuggestColumns', 'the suggestion function', fn);
|
|
177
|
+
return Object.freeze({ __ontos: 'suggest', name: requireName('defineSuggestColumns', name), run: fn as unknown as SuggestColumnsFunction });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// 从描述字面量推出生成类型
|
|
182
|
+
|
|
183
|
+
type Prop<T, K extends PropertyKey> = T extends { readonly [P in K]: infer V } ? V : never;
|
|
184
|
+
type Entries<T> = T extends object ? T : Record<never, never>;
|
|
185
|
+
|
|
186
|
+
type ColumnValue<C> =
|
|
187
|
+
Prop<C, 'type'> extends 'string' | 'date' | 'instant' ? string
|
|
188
|
+
: Prop<C, 'type'> extends 'integer' ? number
|
|
189
|
+
: Prop<C, 'type'> extends 'decimal' ? number | string
|
|
190
|
+
: Prop<C, 'type'> extends 'boolean' ? boolean
|
|
191
|
+
: unknown;
|
|
192
|
+
|
|
193
|
+
type PrimaryKeyOf<T> = Prop<T, 'primaryKey'> extends ReadonlyArray<infer K> ? K & string : never;
|
|
194
|
+
|
|
195
|
+
type RowOf<T> = Simplify<
|
|
196
|
+
{ [K in keyof Entries<Prop<T, 'columns'>> as K extends PrimaryKeyOf<T> ? K : never]: ColumnValue<Entries<Prop<T, 'columns'>>[K]> }
|
|
197
|
+
& { [K in keyof Entries<Prop<T, 'columns'>> as K extends PrimaryKeyOf<T> ? never : K]?: ColumnValue<Entries<Prop<T, 'columns'>>[K]> | null }
|
|
198
|
+
& (Prop<T, 'extensible'> extends true ? { [field: string]: unknown } : unknown)
|
|
199
|
+
>;
|
|
200
|
+
|
|
201
|
+
type ConfigValue<F> =
|
|
202
|
+
Prop<F, 'type'> extends 'string' | 'url' ? string
|
|
203
|
+
: Prop<F, 'type'> extends 'integer' ? number
|
|
204
|
+
: Prop<F, 'type'> extends 'decimal' ? number | string
|
|
205
|
+
: Prop<F, 'type'> extends 'boolean' ? boolean
|
|
206
|
+
: Prop<F, 'type'> extends 'enum' ? (Prop<F, 'values'> extends ReadonlyArray<infer V> ? V : string)
|
|
207
|
+
: unknown;
|
|
208
|
+
|
|
209
|
+
type IsSecret<F> = Prop<F, 'type'> extends 'secret' ? true : false;
|
|
210
|
+
type IsOptional<F> = Prop<F, 'optional'> extends true ? true : false;
|
|
211
|
+
|
|
212
|
+
type ConfigValues<C> = Simplify<
|
|
213
|
+
{ [K in keyof Entries<C> as IsSecret<Entries<C>[K]> extends true ? never : IsOptional<Entries<C>[K]> extends true ? never : K]: ConfigValue<Entries<C>[K]> }
|
|
214
|
+
& { [K in keyof Entries<C> as IsSecret<Entries<C>[K]> extends true ? never : IsOptional<Entries<C>[K]> extends true ? K : never]?: ConfigValue<Entries<C>[K]> }
|
|
215
|
+
>;
|
|
216
|
+
|
|
217
|
+
type SecretValues<C> = Simplify<
|
|
218
|
+
{ [K in keyof Entries<C> as IsSecret<Entries<C>[K]> extends true ? (IsOptional<Entries<C>[K]> extends true ? never : K) : never]: string }
|
|
219
|
+
& { [K in keyof Entries<C> as IsSecret<Entries<C>[K]> extends true ? (IsOptional<Entries<C>[K]> extends true ? K : never) : never]?: string }
|
|
220
|
+
>;
|
|
221
|
+
|
|
222
|
+
type FieldValue<F> =
|
|
223
|
+
Prop<F, 'type'> extends 'object' ? FieldValues<Prop<F, 'fields'>>
|
|
224
|
+
: Prop<F, 'type'> extends 'array' ? Array<FieldValue<Prop<F, 'item'>>>
|
|
225
|
+
: ColumnValue<F>;
|
|
226
|
+
|
|
227
|
+
type FieldValues<Fs> = Simplify<
|
|
228
|
+
{ [K in keyof Entries<Fs> as IsOptional<Entries<Fs>[K]> extends true ? never : K]: FieldValue<Entries<Fs>[K]> }
|
|
229
|
+
& { [K in keyof Entries<Fs> as IsOptional<Entries<Fs>[K]> extends true ? K : never]?: FieldValue<Entries<Fs>[K]> | null }
|
|
230
|
+
>;
|
|
231
|
+
|
|
232
|
+
type TableRows<Tables> = { [T in keyof Entries<Tables>]: RowOf<Entries<Tables>[T]> };
|
|
233
|
+
type ExtensibleRows<Tables> = { [T in keyof Entries<Tables> as Prop<Entries<Tables>[T], 'extensible'> extends true ? T : never]: RowOf<Entries<Tables>[T]> };
|
|
234
|
+
type HasExtensible<Tables> = keyof ExtensibleRows<Tables> extends never ? false : true;
|
|
235
|
+
|
|
236
|
+
/** 描述字面量的最小形状(只读数组也可以,便于 `as const`)。 */
|
|
237
|
+
export interface DescriptorLiteral {
|
|
238
|
+
readonly config: object;
|
|
239
|
+
readonly streams: object;
|
|
240
|
+
readonly pushes: object;
|
|
241
|
+
readonly operations: object;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* 从描述字面量(`as const`)推出 `GeneratedDescriptor`:
|
|
246
|
+
* 列 string / date / instant → string,integer → number,decimal → number | string,boolean → boolean,json → unknown;
|
|
247
|
+
* 配置项 url → string,enum → 取值的联合;操作字段 object / array 递归展开;`optional: true` 的项为可选属性。
|
|
248
|
+
*/
|
|
249
|
+
export type DescriptorTypes<C extends DescriptorLiteral> = {
|
|
250
|
+
config: ConfigValues<C['config']>;
|
|
251
|
+
secrets: SecretValues<C['config']>;
|
|
252
|
+
streams: { [N in keyof Entries<C['streams']>]: { tables: TableRows<Prop<Entries<C['streams']>[N], 'tables'>>; params: ConfigValues<Prop<Entries<C['streams']>[N], 'params'>> } };
|
|
253
|
+
extensibleStreams: {
|
|
254
|
+
[N in keyof Entries<C['streams']> as HasExtensible<Prop<Entries<C['streams']>[N], 'tables'>> extends true ? N : never]: {
|
|
255
|
+
tables: ExtensibleRows<Prop<Entries<C['streams']>[N], 'tables'>>;
|
|
256
|
+
params: ConfigValues<Prop<Entries<C['streams']>[N], 'params'>>;
|
|
257
|
+
};
|
|
258
|
+
};
|
|
259
|
+
pushes: { [N in keyof Entries<C['pushes']>]: { tables: TableRows<Prop<Entries<C['pushes']>[N], 'tables'>> } };
|
|
260
|
+
operations: {
|
|
261
|
+
[N in keyof Entries<C['operations']>]: {
|
|
262
|
+
input: FieldValues<Prop<Entries<C['operations']>[N], 'input'>>;
|
|
263
|
+
output: FieldValues<Prop<Entries<C['operations']>[N], 'output'>>;
|
|
264
|
+
idempotency: Prop<Entries<C['operations']>[N], 'idempotency'> extends 'unsupported' ? 'unsupported' : 'supported';
|
|
265
|
+
};
|
|
266
|
+
};
|
|
267
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 连接器描述(JSON 形式)。
|
|
3
|
+
*
|
|
4
|
+
* 源码包里按能力分目录的 YAML(`ontos-connector.yaml`、`streams/<名>/stream.yaml`…)由平台(shared)解析、校验后规整成这份 JSON:
|
|
5
|
+
* 列的简写已展开,缺省值已补齐。SDK 不解析 YAML,只认这份 JSON:运行时取打包产物里嵌入的 `descriptor`,本地取 `.ontos/descriptor.json`。
|
|
6
|
+
* shared 有一份同形的定义,两者可以互相赋值。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** 多语言文字:纯字符串对所有语言相同;语言表显示时取界面语言 → `en-US` → 第一项。 */
|
|
10
|
+
export type LocalizedText = string | Partial<Record<'zh-CN' | 'en-US', string>>;
|
|
11
|
+
|
|
12
|
+
export type ColumnType = 'string' | 'integer' | 'decimal' | 'boolean' | 'date' | 'instant' | 'json';
|
|
13
|
+
|
|
14
|
+
export interface ColumnDescriptor {
|
|
15
|
+
type: ColumnType;
|
|
16
|
+
/** 只有 `decimal` 有。 */
|
|
17
|
+
precision?: number;
|
|
18
|
+
scale?: number;
|
|
19
|
+
title: LocalizedText;
|
|
20
|
+
description: LocalizedText | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TableDescriptor {
|
|
24
|
+
title: LocalizedText;
|
|
25
|
+
description: LocalizedText;
|
|
26
|
+
primaryKey: string[];
|
|
27
|
+
/** 可扩展:建连接时可以为它加扩展列,记录里的额外字段不算未声明字段。 */
|
|
28
|
+
extensible: boolean;
|
|
29
|
+
columns: Record<string, ColumnDescriptor>;
|
|
30
|
+
retention: { column: string; days: number } | null;
|
|
31
|
+
purgeColumns: { tenant?: string; user?: string } | null;
|
|
32
|
+
indexes: string[][];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 配置项(连接配置与数据流参数)。`secret` 只出现在连接配置里,值走 Secret 引用。 */
|
|
36
|
+
export interface ConfigField {
|
|
37
|
+
type: 'string' | 'url' | 'integer' | 'decimal' | 'boolean' | 'secret' | 'enum';
|
|
38
|
+
title: LocalizedText;
|
|
39
|
+
description: LocalizedText;
|
|
40
|
+
placeholder: LocalizedText | null;
|
|
41
|
+
optional: boolean;
|
|
42
|
+
default?: string | number | boolean;
|
|
43
|
+
/** 只有 `enum` 有。 */
|
|
44
|
+
values?: string[];
|
|
45
|
+
/** 只有 `secret` 有:脚本可取明文(审阅标记,不是安全边界)。 */
|
|
46
|
+
exposeToScript?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 连接器操作的入参与输出字段。 */
|
|
50
|
+
export interface ValueField {
|
|
51
|
+
type: ColumnType | 'object' | 'array';
|
|
52
|
+
title: LocalizedText;
|
|
53
|
+
description: LocalizedText;
|
|
54
|
+
optional: boolean;
|
|
55
|
+
precision?: number;
|
|
56
|
+
scale?: number;
|
|
57
|
+
/** 只有 `object` 有。 */
|
|
58
|
+
fields?: Record<string, ValueField>;
|
|
59
|
+
/** 只有 `array` 有。 */
|
|
60
|
+
item?: ValueField;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface StreamDescriptor {
|
|
64
|
+
title: LocalizedText;
|
|
65
|
+
description: LocalizedText;
|
|
66
|
+
syncModes: Array<'full' | 'incremental'>;
|
|
67
|
+
snapshot: 'complete' | 'partial';
|
|
68
|
+
params: Record<string, ConfigField>;
|
|
69
|
+
tables: Record<string, TableDescriptor>;
|
|
70
|
+
/** 数据流目录里有 `suggest-columns.ts`。 */
|
|
71
|
+
suggestColumns: boolean;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PushDescriptor {
|
|
75
|
+
title: LocalizedText;
|
|
76
|
+
description: LocalizedText;
|
|
77
|
+
tables: Record<string, TableDescriptor>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface OperationDescriptor {
|
|
81
|
+
title: LocalizedText;
|
|
82
|
+
description: LocalizedText;
|
|
83
|
+
effect: 'create' | 'update' | 'delete';
|
|
84
|
+
risk: 'low' | 'medium' | 'high' | 'critical';
|
|
85
|
+
idempotency: 'supported' | 'unsupported';
|
|
86
|
+
input: Record<string, ValueField>;
|
|
87
|
+
output: Record<string, ValueField>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ConnectorDescriptor {
|
|
91
|
+
name: string;
|
|
92
|
+
version: string;
|
|
93
|
+
title: LocalizedText;
|
|
94
|
+
description: LocalizedText;
|
|
95
|
+
icon: 'icon.svg' | 'icon.png' | null;
|
|
96
|
+
config: Record<string, ConfigField>;
|
|
97
|
+
/** 额外的固定出站主机(精确主机名或 `*.后缀`);`url` 配置项的主机自动加入白名单。 */
|
|
98
|
+
hosts: string[];
|
|
99
|
+
db: { engine: 'postgresql' } | null;
|
|
100
|
+
rateLimit: { perSecond: number; concurrency: number } | null;
|
|
101
|
+
/** 根目录有 `check.ts`。 */
|
|
102
|
+
check: boolean;
|
|
103
|
+
streams: Record<string, StreamDescriptor>;
|
|
104
|
+
pushes: Record<string, PushDescriptor>;
|
|
105
|
+
operations: Record<string, OperationDescriptor>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** `suggestColumns` 给出的一条建议列;文字只用单语字符串(由使用者选定后成为扩展列)。 */
|
|
109
|
+
export interface SuggestedColumn {
|
|
110
|
+
name: string;
|
|
111
|
+
type: ColumnType;
|
|
112
|
+
precision?: number;
|
|
113
|
+
scale?: number;
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/** 连接器抛给平台的错误;`code` 稳定,平台据此决定拒收、失败或重试。 */
|
|
2
|
+
export class ConnectorError extends Error {
|
|
3
|
+
readonly code: string;
|
|
4
|
+
|
|
5
|
+
constructor(code: string, message: string) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ConnectorError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** 凭证失效:停止运行,连接标为凭证失效。 */
|
|
13
|
+
class AuthError extends ConnectorError {
|
|
14
|
+
constructor(message: string) {
|
|
15
|
+
super('AUTH_ERROR', message);
|
|
16
|
+
this.name = 'AuthError';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 被来源限流:等 `retryAfterMs` 后重试当前请求。 */
|
|
21
|
+
class RateLimited extends ConnectorError {
|
|
22
|
+
readonly retryAfterMs: number;
|
|
23
|
+
|
|
24
|
+
constructor(retryAfterMs: number, message?: string) {
|
|
25
|
+
super('RATE_LIMITED', message ?? `rate limited, retry after ${retryAfterMs} ms`);
|
|
26
|
+
this.name = 'RateLimited';
|
|
27
|
+
this.retryAfterMs = retryAfterMs;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** 瞬时错误:指数退避重试当前请求,超过次数后运行失败,下次从断点续跑。 */
|
|
32
|
+
class TransientError extends ConnectorError {
|
|
33
|
+
constructor(message: string) {
|
|
34
|
+
super('TRANSIENT_ERROR', message);
|
|
35
|
+
this.name = 'TransientError';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
class SchemaError extends ConnectorError {
|
|
40
|
+
constructor(message: string) {
|
|
41
|
+
super('SCHEMA_ERROR', message);
|
|
42
|
+
this.name = 'SchemaError';
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class FatalError extends ConnectorError {
|
|
47
|
+
constructor(message: string) {
|
|
48
|
+
super('FATAL_ERROR', message);
|
|
49
|
+
this.name = 'FatalError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
class RejectedPayload extends ConnectorError {
|
|
54
|
+
constructor(message: string) {
|
|
55
|
+
super('REJECTED_PAYLOAD', message);
|
|
56
|
+
this.name = 'RejectedPayload';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 连接器操作:外部系统明确拒绝(如库存不足)。平台不重试;`details.code` 是外部系统的业务码。 */
|
|
61
|
+
class RejectedError extends ConnectorError {
|
|
62
|
+
readonly details: { code?: string } | undefined;
|
|
63
|
+
|
|
64
|
+
constructor(message: string, details?: { code?: string }) {
|
|
65
|
+
super('REJECTED', message);
|
|
66
|
+
this.name = 'RejectedError';
|
|
67
|
+
this.details = details;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** 连接器操作:不知道外部系统是否已经执行(如请求发出后连接断开)。平台不重发,转入查询确认。 */
|
|
72
|
+
class IndeterminateError extends ConnectorError {
|
|
73
|
+
constructor(message: string) {
|
|
74
|
+
super('INDETERMINATE', message);
|
|
75
|
+
this.name = 'IndeterminateError';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** 保留名字但尚未开放的能力(如 `ctx.files`)。 */
|
|
80
|
+
class NotAvailable extends ConnectorError {
|
|
81
|
+
constructor(feature: string) {
|
|
82
|
+
super('NOT_AVAILABLE', `${feature} is not available yet`);
|
|
83
|
+
this.name = 'NotAvailable';
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface RateLimitedError extends ConnectorError {
|
|
88
|
+
readonly retryAfterMs: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RejectedOperationError extends ConnectorError {
|
|
92
|
+
readonly details: { code?: string } | undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const errors: {
|
|
96
|
+
AuthError: new (message: string) => ConnectorError;
|
|
97
|
+
RateLimited: new (retryAfterMs: number, message?: string) => RateLimitedError;
|
|
98
|
+
TransientError: new (message: string) => ConnectorError;
|
|
99
|
+
SchemaError: new (message: string) => ConnectorError;
|
|
100
|
+
FatalError: new (message: string) => ConnectorError;
|
|
101
|
+
RejectedPayload: new (message: string) => ConnectorError;
|
|
102
|
+
NotAvailable: new (feature: string) => ConnectorError;
|
|
103
|
+
RejectedError: new (message: string, details?: { code?: string }) => RejectedOperationError;
|
|
104
|
+
IndeterminateError: new (message: string) => ConnectorError;
|
|
105
|
+
} = Object.freeze({ AuthError, RateLimited, TransientError, SchemaError, FatalError, RejectedPayload, NotAvailable, RejectedError, IndeterminateError });
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
ArrayType,
|
|
3
|
+
CheckContext,
|
|
4
|
+
CheckpointItem,
|
|
5
|
+
ConnectorCache,
|
|
6
|
+
ConnectorCrypto,
|
|
7
|
+
ConnectorDb,
|
|
8
|
+
ConnectorLog,
|
|
9
|
+
ConnectorOperationEffect,
|
|
10
|
+
ConnectorOperationRisk,
|
|
11
|
+
ConnectorRateLimit,
|
|
12
|
+
ConnectorSignal,
|
|
13
|
+
ConnectorTime,
|
|
14
|
+
CursorPaginateOptions,
|
|
15
|
+
DigestEncoding,
|
|
16
|
+
HashAlgorithm,
|
|
17
|
+
HmacAlgorithm,
|
|
18
|
+
HttpAuth,
|
|
19
|
+
HttpClient,
|
|
20
|
+
HttpMethod,
|
|
21
|
+
HttpOptions,
|
|
22
|
+
HttpResponse,
|
|
23
|
+
KeysetPaginateOptions,
|
|
24
|
+
LinkPaginateOptions,
|
|
25
|
+
LookupResult,
|
|
26
|
+
ObjectType,
|
|
27
|
+
OffsetPaginateOptions,
|
|
28
|
+
OperationContext,
|
|
29
|
+
OperationHandlers,
|
|
30
|
+
Page,
|
|
31
|
+
PagePaginateOptions,
|
|
32
|
+
Paginate,
|
|
33
|
+
PullContext,
|
|
34
|
+
PushContext,
|
|
35
|
+
PushHandler,
|
|
36
|
+
PushRequest,
|
|
37
|
+
RecordItem,
|
|
38
|
+
RemoveItem,
|
|
39
|
+
ScalarKind,
|
|
40
|
+
ScalarType,
|
|
41
|
+
SdkType,
|
|
42
|
+
SecretType,
|
|
43
|
+
SignAlgorithm,
|
|
44
|
+
StreamFunction,
|
|
45
|
+
StreamInput,
|
|
46
|
+
StreamItem,
|
|
47
|
+
SyncMode,
|
|
48
|
+
TableDeclaration,
|
|
49
|
+
} from './types';
|
|
50
|
+
export type {
|
|
51
|
+
ColumnDescriptor,
|
|
52
|
+
ColumnType,
|
|
53
|
+
ConfigField,
|
|
54
|
+
ConnectorDescriptor,
|
|
55
|
+
LocalizedText,
|
|
56
|
+
OperationDescriptor,
|
|
57
|
+
PushDescriptor,
|
|
58
|
+
StreamDescriptor,
|
|
59
|
+
SuggestedColumn,
|
|
60
|
+
TableDescriptor,
|
|
61
|
+
ValueField,
|
|
62
|
+
} from './descriptor';
|
|
63
|
+
export type {
|
|
64
|
+
CheckFn,
|
|
65
|
+
CheckImpl,
|
|
66
|
+
ConnectorContext,
|
|
67
|
+
DescriptorLiteral,
|
|
68
|
+
DescriptorTypes,
|
|
69
|
+
GeneratedDescriptor,
|
|
70
|
+
GeneratedOperation,
|
|
71
|
+
GeneratedPush,
|
|
72
|
+
GeneratedRow,
|
|
73
|
+
GeneratedStream,
|
|
74
|
+
OperationContextOf,
|
|
75
|
+
OperationImpl,
|
|
76
|
+
OperationImplBrand,
|
|
77
|
+
PushContextOf,
|
|
78
|
+
PushImpl,
|
|
79
|
+
PushImplBrand,
|
|
80
|
+
StreamContext,
|
|
81
|
+
StreamFn,
|
|
82
|
+
StreamImpl,
|
|
83
|
+
StreamInputOf,
|
|
84
|
+
SuggestColumnsFunction,
|
|
85
|
+
SuggestFn,
|
|
86
|
+
SuggestImpl,
|
|
87
|
+
} from './define';
|
|
88
|
+
export { defineCheck, defineOperation, definePush, defineStream, defineSuggestColumns } from './define';
|
|
89
|
+
export type { RateLimitedError, RejectedOperationError } from './errors';
|
|
90
|
+
export { ConnectorError, errors } from './errors';
|
|
91
|
+
export type { DeclarationIssue } from './validate';
|
|
92
|
+
export {
|
|
93
|
+
DEFAULT_PUSH_NAME,
|
|
94
|
+
OPERATION_NAME_PATTERN,
|
|
95
|
+
PRESENTATION_LIMITS,
|
|
96
|
+
RESERVED_PUSH_NAMES,
|
|
97
|
+
SDK_NAME_PATTERN,
|
|
98
|
+
SUGGESTED_COLUMNS_MAX,
|
|
99
|
+
validateConfig,
|
|
100
|
+
validateOperationValue,
|
|
101
|
+
validateSuggestedColumns,
|
|
102
|
+
} from './validate';
|
|
103
|
+
|
|
104
|
+
/** SDK 版本,等于本包 `package.json` 的 `version`;meta 打包校验 `dependencies` 范围与 runner 都用它。 */
|
|
105
|
+
export const SDK_VERSION: string = '3.1.0';
|
|
106
|
+
|
|
107
|
+
/** runner 支持的 SDK 主版本集合;连接器 `dependencies` 里 SDK 的下限主版本必须在其中。 */
|
|
108
|
+
export const SUPPORTED_SDK_MAJORS: readonly number[] = [3];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 包内文件定位(宿主侧,不进 guest)。同一份源码有三种运行形态:
|
|
3
|
+
* - 源码(Bun 直接执行 `src/*.ts`,工作区里的 runner、connector 与测试):`PACKAGE_ROOT` 是 `src/`;
|
|
4
|
+
* - dist 的 ESM(`dist/**\/*.js`,tsc 编译):`PACKAGE_ROOT` 是 `dist/`;
|
|
5
|
+
* - dist 的 CJS(`dist/cjs/*.cjs`,构建脚本打包时用 `__dirname` 版本替换本模块):`PACKAGE_ROOT` 同样是 `dist/`。
|
|
6
|
+
*
|
|
7
|
+
* 本文件只用 `import.meta.url`,不用 Bun 专有的 `import.meta.dir`,Node 下同样可用。
|
|
8
|
+
*/
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
|
|
12
|
+
const self = fileURLToPath(import.meta.url);
|
|
13
|
+
|
|
14
|
+
/** 当前是否直接从源码(`.ts`)执行。 */
|
|
15
|
+
export const IS_SOURCE: boolean = self.endsWith('.ts');
|
|
16
|
+
|
|
17
|
+
/** `src/`(源码)或 `dist/`(构建产物)。 */
|
|
18
|
+
export const PACKAGE_ROOT: string = path.resolve(path.dirname(self), '..');
|
|
19
|
+
|
|
20
|
+
/** 源码与 dist 下同一模块的路径:`relative` 不带扩展名,源码取 `.ts`,dist 取 `.js`。 */
|
|
21
|
+
export function moduleFile(relative: string): string {
|
|
22
|
+
return path.join(PACKAGE_ROOT, `${relative}${IS_SOURCE ? '.ts' : '.js'}`);
|
|
23
|
+
}
|