web-dc-api 0.0.73 → 0.0.75
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/dc.min.js +15 -3
- package/dist/index.cjs.js +15 -3
- package/dist/index.d.ts +445 -23
- package/dist/index.esm.js +15 -3
- package/lib/implements/aiproxy/manager.ts +7 -7
- package/lib/implements/keyvalue/client.ts +4 -4
- package/lib/implements/keyvalue/manager.ts +13 -11
- package/lib/implements/threaddb/common/key.ts +1 -1
- package/lib/index.ts +4 -0
- package/lib/interfaces/keyvalue-interface.ts +17 -6
- package/lib/modules/keyvalue-module.ts +25 -7
- package/lib/polyfills/process-env-browser.ts +1 -0
- package/lib/proto/dcnet.proto +1 -0
- package/lib/proto/dcnet_proto.d.ts +251 -0
- package/lib/proto/dcnet_proto.js +649 -1
- package/lib/serverless/babel-browser.ts +39 -0
- package/lib/serverless/base_entity.ts +78 -0
- package/lib/serverless/base_repository.ts +284 -0
- package/lib/serverless/browser_schema_extractor.ts +283 -0
- package/lib/serverless/decorator_factory.ts +322 -0
- package/package.json +4 -1
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/* Serverless-friendly decorators (TS 5 standard + legacy)
|
|
2
|
+
- @Entity(options?)
|
|
3
|
+
- @Column(options?)
|
|
4
|
+
- @Index(nameOrOptions[, fields])
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type PrimitiveType = 'string' | 'number' | 'boolean' | 'date' | 'json' | 'binary';
|
|
8
|
+
|
|
9
|
+
export interface EntityOptions {
|
|
10
|
+
name?: string; // 实体名(默认类名)
|
|
11
|
+
namespace?: string; // 可选命名空间/前缀
|
|
12
|
+
ttlSeconds?: number; // 过期秒数,用于 serverless KV/缓存等
|
|
13
|
+
versioned?: boolean; // 是否启用版本
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ColumnOptions<T = unknown> {
|
|
17
|
+
name?: string; // 存储层字段名(默认属性名)
|
|
18
|
+
type?: PrimitiveType; // 简化类型映射
|
|
19
|
+
required?: boolean; // 是否必填
|
|
20
|
+
default?: T | (() => T); // 默认值
|
|
21
|
+
index?: boolean; // 单列索引
|
|
22
|
+
unique?: boolean; // 唯一约束(需要底层支持)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type IndexField =
|
|
26
|
+
| string
|
|
27
|
+
| { field: string; order?: 'asc' | 'desc' };
|
|
28
|
+
|
|
29
|
+
export interface IndexOptions {
|
|
30
|
+
name?: string;
|
|
31
|
+
fields: IndexField[];
|
|
32
|
+
unique?: boolean;
|
|
33
|
+
ttlSeconds?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface EntityMeta {
|
|
37
|
+
target: Function;
|
|
38
|
+
name: string;
|
|
39
|
+
options: EntityOptions;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface ColumnMeta {
|
|
43
|
+
target: Function;
|
|
44
|
+
propertyKey: string | symbol;
|
|
45
|
+
options: ColumnOptions;
|
|
46
|
+
resolvedName: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface NormalizedIndexField {
|
|
50
|
+
field: string;
|
|
51
|
+
order: 'asc' | 'desc';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface IndexMeta {
|
|
55
|
+
target: Function;
|
|
56
|
+
name: string;
|
|
57
|
+
fields: NormalizedIndexField[];
|
|
58
|
+
unique?: boolean;
|
|
59
|
+
ttlSeconds?: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type StdDecoratorContext = {
|
|
63
|
+
kind: 'class' | 'field' | 'accessor' | 'method' | 'getter' | 'setter';
|
|
64
|
+
name?: string | symbol;
|
|
65
|
+
addInitializer?: (fn: () => void) => void;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function isStdCtx(v: unknown): v is StdDecoratorContext {
|
|
69
|
+
return !!v && typeof v === 'object' && 'kind' in (v as any);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
class MetadataStorage {
|
|
73
|
+
private entities = new WeakMap<Function, EntityMeta>();
|
|
74
|
+
private columns = new WeakMap<Function, Map<string | symbol, ColumnMeta>>();
|
|
75
|
+
private indexes = new WeakMap<Function, IndexMeta[]>();
|
|
76
|
+
|
|
77
|
+
registerEntity(target: Function, options: EntityOptions = {}, nameHint?: string) {
|
|
78
|
+
const name = options.name ?? nameHint ?? target.name;
|
|
79
|
+
const meta: EntityMeta = { target, name, options: { ...options, name } };
|
|
80
|
+
this.entities.set(target, meta);
|
|
81
|
+
return meta;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
registerColumn(target: Function, propertyKey: string | symbol, options: ColumnOptions = {}) {
|
|
85
|
+
const colMap = this.columns.get(target) ?? new Map();
|
|
86
|
+
const resolvedName = options.name ?? String(propertyKey);
|
|
87
|
+
const meta: ColumnMeta = { target, propertyKey, options, resolvedName };
|
|
88
|
+
colMap.set(propertyKey, meta);
|
|
89
|
+
this.columns.set(target, colMap);
|
|
90
|
+
return meta;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
registerIndex(target: Function, input: { name?: string; fields: IndexField[]; unique?: boolean; ttlSeconds?: number }) {
|
|
94
|
+
if (!input.fields || input.fields.length === 0) {
|
|
95
|
+
throw new Error('@Index requires at least one field');
|
|
96
|
+
}
|
|
97
|
+
const normalizedFields: NormalizedIndexField[] = input.fields.map(f =>
|
|
98
|
+
typeof f === 'string' ? { field: f, order: 'asc' } : { field: f.field, order: f.order ?? 'asc' }
|
|
99
|
+
);
|
|
100
|
+
const name = input.name ?? this.defaultIndexName(normalizedFields);
|
|
101
|
+
|
|
102
|
+
const arr = this.indexes.get(target) ?? [];
|
|
103
|
+
const dedupKey = this.makeIndexKey(name, normalizedFields);
|
|
104
|
+
const exists = arr.some(i => this.makeIndexKey(i.name, i.fields) === dedupKey);
|
|
105
|
+
|
|
106
|
+
if (!exists) {
|
|
107
|
+
const norm: IndexMeta = {
|
|
108
|
+
target,
|
|
109
|
+
name,
|
|
110
|
+
fields: normalizedFields,
|
|
111
|
+
...(input.unique !== undefined ? { unique: input.unique } : {}),
|
|
112
|
+
...(input.ttlSeconds !== undefined ? { ttlSeconds: input.ttlSeconds } : {}),
|
|
113
|
+
};
|
|
114
|
+
arr.push(norm);
|
|
115
|
+
this.indexes.set(target, arr);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
getEntity(target: Function | object): EntityMeta | undefined {
|
|
120
|
+
const ctor = typeof target === 'function' ? target : (target as any)?.constructor;
|
|
121
|
+
return this.entities.get(ctor);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getColumns(target: Function | object): ColumnMeta[] {
|
|
125
|
+
const ctor = typeof target === 'function' ? target : (target as any)?.constructor;
|
|
126
|
+
const map = this.columns.get(ctor);
|
|
127
|
+
return map ? Array.from(map.values()) : [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getIndexes(target: Function | object): IndexMeta[] {
|
|
131
|
+
const ctor = typeof target === 'function' ? target : (target as any)?.constructor;
|
|
132
|
+
return this.indexes.get(ctor) ?? [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getSchema(target: Function | object) {
|
|
136
|
+
return {
|
|
137
|
+
entity: this.getEntity(target),
|
|
138
|
+
columns: this.getColumns(target),
|
|
139
|
+
indexes: this.getIndexes(target),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private defaultIndexName(fields: NormalizedIndexField[]) {
|
|
144
|
+
const part = fields.map(f => `${f.field}_${f.order}`).join('_');
|
|
145
|
+
return `idx_${part}`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private makeIndexKey(name: string, fields: NormalizedIndexField[]) {
|
|
149
|
+
return `${name}|${fields.map(f => `${f.field}:${f.order}`).join(',')}`;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export const metadata = new MetadataStorage();
|
|
154
|
+
|
|
155
|
+
// ---------- Decorators (dual-mode: standard + legacy) ----------
|
|
156
|
+
|
|
157
|
+
export function Entity(options: EntityOptions = {}) {
|
|
158
|
+
// Standard: (value, context)
|
|
159
|
+
// Legacy: (ctor)
|
|
160
|
+
return function entityDecorator(valueOrTarget: any, maybeContext?: unknown) {
|
|
161
|
+
if (isStdCtx(maybeContext) && maybeContext.kind === 'class') {
|
|
162
|
+
const ctor = valueOrTarget as Function;
|
|
163
|
+
metadata.registerEntity(ctor, options, maybeContext.name ? String(maybeContext.name) : undefined);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Legacy
|
|
167
|
+
const ctor = valueOrTarget as Function;
|
|
168
|
+
metadata.registerEntity(ctor, options, ctor.name);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function Column(options: ColumnOptions = {}) {
|
|
173
|
+
// Standard: (initialValue, context)
|
|
174
|
+
// Legacy: (target, propertyKey)
|
|
175
|
+
return function columnDecorator(a: any, b: any) {
|
|
176
|
+
// Standard field/accessor
|
|
177
|
+
if (isStdCtx(b) && (b.kind === 'field' || b.kind === 'accessor')) {
|
|
178
|
+
const ctx = b as StdDecoratorContext;
|
|
179
|
+
const prop = ctx.name as string | symbol;
|
|
180
|
+
|
|
181
|
+
ctx.addInitializer?.(function (this: any) {
|
|
182
|
+
const ctor = this?.constructor;
|
|
183
|
+
if (!ctor) return;
|
|
184
|
+
const colMeta = metadata.registerColumn(ctor, prop, options);
|
|
185
|
+
if (options.index || options.unique) {
|
|
186
|
+
metadata.registerIndex(ctor, {
|
|
187
|
+
name: `idx_${String(colMeta.resolvedName)}`,
|
|
188
|
+
fields: [String(colMeta.resolvedName)],
|
|
189
|
+
...(options.unique !== undefined ? { unique: options.unique } : {}),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
// Legacy property decorator
|
|
196
|
+
const target = a;
|
|
197
|
+
const propertyKey = b as string | symbol;
|
|
198
|
+
const ctor = target?.constructor;
|
|
199
|
+
const colMeta = metadata.registerColumn(ctor, propertyKey, options);
|
|
200
|
+
if (options.index || options.unique) {
|
|
201
|
+
metadata.registerIndex(ctor, {
|
|
202
|
+
name: `idx_${String(colMeta.resolvedName)}`,
|
|
203
|
+
fields: [String(colMeta.resolvedName)],
|
|
204
|
+
...(options.unique !== undefined ? { unique: options.unique } : {}),
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function Index(nameOrOptions: string | IndexOptions, fields?: IndexOptions['fields']) {
|
|
211
|
+
return function indexDecorator(valueOrTarget: any, maybeContext?: unknown) {
|
|
212
|
+
// Standard mode
|
|
213
|
+
if (isStdCtx(maybeContext)) {
|
|
214
|
+
const ctx = maybeContext as StdDecoratorContext;
|
|
215
|
+
|
|
216
|
+
if (ctx.kind === 'class') {
|
|
217
|
+
const ctor = valueOrTarget as Function;
|
|
218
|
+
const opts: IndexOptions = typeof nameOrOptions === 'string'
|
|
219
|
+
? { name: nameOrOptions, fields: fields ?? [] }
|
|
220
|
+
: nameOrOptions;
|
|
221
|
+
if (!opts.fields || opts.fields.length === 0) {
|
|
222
|
+
throw new Error(`@Index on class ${ctx.name?.toString() ?? ctor.name} requires fields`);
|
|
223
|
+
}
|
|
224
|
+
metadata.registerIndex(ctor, opts as any);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (ctx.kind === 'field' || ctx.kind === 'accessor') {
|
|
229
|
+
const prop = ctx.name as string | symbol;
|
|
230
|
+
const base: IndexOptions =
|
|
231
|
+
typeof nameOrOptions === 'string'
|
|
232
|
+
? { name: nameOrOptions, fields: [String(prop)] }
|
|
233
|
+
: { ...(nameOrOptions ?? {}), fields: (nameOrOptions as IndexOptions)?.fields?.length ? (nameOrOptions as IndexOptions).fields : [String(prop)] };
|
|
234
|
+
|
|
235
|
+
ctx.addInitializer?.(function (this: any) {
|
|
236
|
+
const ctor = this?.constructor;
|
|
237
|
+
if (!ctor) return;
|
|
238
|
+
metadata.registerIndex(ctor, {
|
|
239
|
+
...(base.name ? { name: base.name } : {}),
|
|
240
|
+
fields: base.fields,
|
|
241
|
+
...(base.unique !== undefined ? { unique: base.unique } : {}),
|
|
242
|
+
...(base.ttlSeconds !== undefined ? { ttlSeconds: base.ttlSeconds } : {}),
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Legacy mode
|
|
250
|
+
if (typeof maybeContext === 'string' || typeof maybeContext === 'symbol') {
|
|
251
|
+
// Property decorator
|
|
252
|
+
const target = valueOrTarget;
|
|
253
|
+
const prop = maybeContext as string | symbol;
|
|
254
|
+
const ctor = target?.constructor;
|
|
255
|
+
const base: IndexOptions =
|
|
256
|
+
typeof nameOrOptions === 'string'
|
|
257
|
+
? { name: nameOrOptions, fields: [String(prop)] }
|
|
258
|
+
: { ...(nameOrOptions ?? {}), fields: (nameOrOptions as IndexOptions)?.fields?.length ? (nameOrOptions as IndexOptions).fields : [String(prop)] };
|
|
259
|
+
|
|
260
|
+
metadata.registerIndex(ctor, {
|
|
261
|
+
...(base.name ? { name: base.name } : {}),
|
|
262
|
+
fields: base.fields,
|
|
263
|
+
...(base.unique !== undefined ? { unique: base.unique } : {}),
|
|
264
|
+
...(base.ttlSeconds !== undefined ? { ttlSeconds: base.ttlSeconds } : {}),
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
// Class decorator
|
|
268
|
+
const ctor = valueOrTarget as Function;
|
|
269
|
+
const opts: IndexOptions =
|
|
270
|
+
typeof nameOrOptions === 'string'
|
|
271
|
+
? { name: nameOrOptions, fields: fields ?? [] }
|
|
272
|
+
: nameOrOptions;
|
|
273
|
+
|
|
274
|
+
if (!opts.fields || opts.fields.length === 0) {
|
|
275
|
+
throw new Error(`@Index on class ${ctor.name} requires fields`);
|
|
276
|
+
}
|
|
277
|
+
metadata.registerIndex(ctor, {
|
|
278
|
+
...(opts.name ? { name: opts.name } : {}),
|
|
279
|
+
fields: opts.fields,
|
|
280
|
+
...(opts.unique !== undefined ? { unique: opts.unique } : {}),
|
|
281
|
+
...(opts.ttlSeconds !== undefined ? { ttlSeconds: opts.ttlSeconds } : {}),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ---------- Helpers for consumers ----------
|
|
288
|
+
|
|
289
|
+
export function getEntitySchema(target: Function | object) {
|
|
290
|
+
return metadata.getSchema(target);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function getEntityName(target: Function | object) {
|
|
294
|
+
return metadata.getEntity(target)?.name;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function getColumns(target: Function | object) {
|
|
298
|
+
return metadata.getColumns(target);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function getIndexes(target: Function | object) {
|
|
302
|
+
return metadata.getIndexes(target);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/*
|
|
306
|
+
Usage example:
|
|
307
|
+
|
|
308
|
+
@Entity({ name: 'User', namespace: 'app', ttlSeconds: 86400 })
|
|
309
|
+
class User {
|
|
310
|
+
@Column({ type: 'string', required: true })
|
|
311
|
+
id!: string;
|
|
312
|
+
|
|
313
|
+
@Column({ type: 'string', index: true })
|
|
314
|
+
email!: string;
|
|
315
|
+
|
|
316
|
+
@Column({ type: 'date', default: () => new Date() })
|
|
317
|
+
createdAt!: Date;
|
|
318
|
+
|
|
319
|
+
@Index('idx_email_unique', ['email'])
|
|
320
|
+
// or put @Index() on the field to use single-column default index
|
|
321
|
+
}
|
|
322
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web-dc-api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.75",
|
|
4
4
|
"description": "web相关的dcapi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"browser": "dist/dc.min.js",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"license": "ISC",
|
|
34
34
|
"keywords": [],
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@babel/parser": "^7.28.4",
|
|
37
|
+
"@babel/traverse": "^7.28.4",
|
|
38
|
+
"@babel/types": "^7.28.4",
|
|
36
39
|
"@helia/block-brokers": "4.1.0",
|
|
37
40
|
"@helia/dag-cbor": "^4.0.3",
|
|
38
41
|
"@helia/interface": "4.0.1",
|