@xiaoxiamimengfb/my-opencode-mem 2.12.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 +155 -0
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +411 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +427 -0
- package/dist/plugin.d.ts +5 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +4 -0
- package/dist/services/ai/ai-provider-factory.d.ts +8 -0
- package/dist/services/ai/ai-provider-factory.d.ts.map +1 -0
- package/dist/services/ai/ai-provider-factory.js +28 -0
- package/dist/services/ai/opencode-provider.d.ts +30 -0
- package/dist/services/ai/opencode-provider.d.ts.map +1 -0
- package/dist/services/ai/opencode-provider.js +332 -0
- package/dist/services/ai/provider-config.d.ts +17 -0
- package/dist/services/ai/provider-config.d.ts.map +1 -0
- package/dist/services/ai/provider-config.js +14 -0
- package/dist/services/ai/providers/anthropic-messages.d.ts +12 -0
- package/dist/services/ai/providers/anthropic-messages.d.ts.map +1 -0
- package/dist/services/ai/providers/anthropic-messages.js +184 -0
- package/dist/services/ai/providers/base-provider.d.ts +25 -0
- package/dist/services/ai/providers/base-provider.d.ts.map +1 -0
- package/dist/services/ai/providers/base-provider.js +23 -0
- package/dist/services/ai/providers/google-gemini.d.ts +16 -0
- package/dist/services/ai/providers/google-gemini.d.ts.map +1 -0
- package/dist/services/ai/providers/google-gemini.js +228 -0
- package/dist/services/ai/providers/openai-chat-completion.d.ts +13 -0
- package/dist/services/ai/providers/openai-chat-completion.d.ts.map +1 -0
- package/dist/services/ai/providers/openai-chat-completion.js +277 -0
- package/dist/services/ai/providers/openai-responses.d.ts +14 -0
- package/dist/services/ai/providers/openai-responses.d.ts.map +1 -0
- package/dist/services/ai/providers/openai-responses.js +182 -0
- package/dist/services/ai/session/ai-session-manager.d.ts +21 -0
- package/dist/services/ai/session/ai-session-manager.d.ts.map +1 -0
- package/dist/services/ai/session/ai-session-manager.js +166 -0
- package/dist/services/ai/session/session-types.d.ts +43 -0
- package/dist/services/ai/session/session-types.d.ts.map +1 -0
- package/dist/services/ai/session/session-types.js +1 -0
- package/dist/services/ai/tools/tool-schema.d.ts +41 -0
- package/dist/services/ai/tools/tool-schema.d.ts.map +1 -0
- package/dist/services/ai/tools/tool-schema.js +24 -0
- package/dist/services/ai/validators/user-profile-validator.d.ts +13 -0
- package/dist/services/ai/validators/user-profile-validator.d.ts.map +1 -0
- package/dist/services/ai/validators/user-profile-validator.js +111 -0
- package/dist/services/api-handlers.d.ts +164 -0
- package/dist/services/api-handlers.d.ts.map +1 -0
- package/dist/services/api-handlers.js +901 -0
- package/dist/services/auto-capture.d.ts +3 -0
- package/dist/services/auto-capture.d.ts.map +1 -0
- package/dist/services/auto-capture.js +306 -0
- package/dist/services/cleanup-service.d.ts +23 -0
- package/dist/services/cleanup-service.d.ts.map +1 -0
- package/dist/services/cleanup-service.js +102 -0
- package/dist/services/client.d.ts +118 -0
- package/dist/services/client.d.ts.map +1 -0
- package/dist/services/client.js +251 -0
- package/dist/services/context.d.ts +11 -0
- package/dist/services/context.d.ts.map +1 -0
- package/dist/services/context.js +24 -0
- package/dist/services/deduplication-service.d.ts +30 -0
- package/dist/services/deduplication-service.d.ts.map +1 -0
- package/dist/services/deduplication-service.js +124 -0
- package/dist/services/embedding.d.ts +15 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +106 -0
- package/dist/services/jsonc.d.ts +7 -0
- package/dist/services/jsonc.d.ts.map +1 -0
- package/dist/services/jsonc.js +76 -0
- package/dist/services/language-detector.d.ts +3 -0
- package/dist/services/language-detector.d.ts.map +1 -0
- package/dist/services/language-detector.js +16 -0
- package/dist/services/logger.d.ts +2 -0
- package/dist/services/logger.d.ts.map +1 -0
- package/dist/services/logger.js +51 -0
- package/dist/services/migration-service.d.ts +42 -0
- package/dist/services/migration-service.d.ts.map +1 -0
- package/dist/services/migration-service.js +250 -0
- package/dist/services/privacy.d.ts +3 -0
- package/dist/services/privacy.d.ts.map +1 -0
- package/dist/services/privacy.js +7 -0
- package/dist/services/secret-resolver.d.ts +2 -0
- package/dist/services/secret-resolver.d.ts.map +1 -0
- package/dist/services/secret-resolver.js +55 -0
- package/dist/services/sqlite/connection-manager.d.ts +13 -0
- package/dist/services/sqlite/connection-manager.d.ts.map +1 -0
- package/dist/services/sqlite/connection-manager.js +74 -0
- package/dist/services/sqlite/shard-manager.d.ts +23 -0
- package/dist/services/sqlite/shard-manager.d.ts.map +1 -0
- package/dist/services/sqlite/shard-manager.js +288 -0
- package/dist/services/sqlite/sqlite-bootstrap.d.ts +2 -0
- package/dist/services/sqlite/sqlite-bootstrap.d.ts.map +1 -0
- package/dist/services/sqlite/sqlite-bootstrap.js +8 -0
- package/dist/services/sqlite/types.d.ts +42 -0
- package/dist/services/sqlite/types.d.ts.map +1 -0
- package/dist/services/sqlite/types.js +1 -0
- package/dist/services/sqlite/vector-search.d.ts +29 -0
- package/dist/services/sqlite/vector-search.d.ts.map +1 -0
- package/dist/services/sqlite/vector-search.js +268 -0
- package/dist/services/tags.d.ts +24 -0
- package/dist/services/tags.d.ts.map +1 -0
- package/dist/services/tags.js +146 -0
- package/dist/services/user-memory-learning.d.ts +3 -0
- package/dist/services/user-memory-learning.d.ts.map +1 -0
- package/dist/services/user-memory-learning.js +231 -0
- package/dist/services/user-profile/profile-context.d.ts +2 -0
- package/dist/services/user-profile/profile-context.d.ts.map +1 -0
- package/dist/services/user-profile/profile-context.js +40 -0
- package/dist/services/user-profile/profile-utils.d.ts +3 -0
- package/dist/services/user-profile/profile-utils.d.ts.map +1 -0
- package/dist/services/user-profile/profile-utils.js +45 -0
- package/dist/services/user-profile/types.d.ts +46 -0
- package/dist/services/user-profile/types.d.ts.map +1 -0
- package/dist/services/user-profile/types.js +1 -0
- package/dist/services/user-profile/user-profile-manager.d.ts +23 -0
- package/dist/services/user-profile/user-profile-manager.d.ts.map +1 -0
- package/dist/services/user-profile/user-profile-manager.js +292 -0
- package/dist/services/user-prompt/user-prompt-manager.d.ts +41 -0
- package/dist/services/user-prompt/user-prompt-manager.d.ts.map +1 -0
- package/dist/services/user-prompt/user-prompt-manager.js +192 -0
- package/dist/services/vector-backends/backend-factory.d.ts +3 -0
- package/dist/services/vector-backends/backend-factory.d.ts.map +1 -0
- package/dist/services/vector-backends/backend-factory.js +104 -0
- package/dist/services/vector-backends/exact-scan-backend.d.ts +39 -0
- package/dist/services/vector-backends/exact-scan-backend.d.ts.map +1 -0
- package/dist/services/vector-backends/exact-scan-backend.js +63 -0
- package/dist/services/vector-backends/types.d.ts +51 -0
- package/dist/services/vector-backends/types.d.ts.map +1 -0
- package/dist/services/vector-backends/types.js +1 -0
- package/dist/services/vector-backends/usearch-backend.d.ts +47 -0
- package/dist/services/vector-backends/usearch-backend.d.ts.map +1 -0
- package/dist/services/vector-backends/usearch-backend.js +174 -0
- package/dist/services/web-server-worker.d.ts +2 -0
- package/dist/services/web-server-worker.d.ts.map +1 -0
- package/dist/services/web-server-worker.js +283 -0
- package/dist/services/web-server.d.ts +31 -0
- package/dist/services/web-server.d.ts.map +1 -0
- package/dist/services/web-server.js +356 -0
- package/dist/types/index.d.ts +19 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/web/app.d.ts +2 -0
- package/dist/web/app.d.ts.map +1 -0
- package/dist/web/app.js +1194 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/i18n.d.ts +2 -0
- package/dist/web/i18n.d.ts.map +1 -0
- package/dist/web/i18n.js +265 -0
- package/dist/web/index.html +284 -0
- package/dist/web/styles.css +1631 -0
- package/package.json +71 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export class ExactScanBackend {
|
|
2
|
+
getBackendName() {
|
|
3
|
+
return "exact-scan";
|
|
4
|
+
}
|
|
5
|
+
rankVectors(rows, queryVector, limit) {
|
|
6
|
+
return rows
|
|
7
|
+
.map((row) => ({
|
|
8
|
+
id: row.id,
|
|
9
|
+
distance: 1 - this.cosineSimilarity(row.vector, queryVector),
|
|
10
|
+
}))
|
|
11
|
+
.sort((a, b) => a.distance - b.distance)
|
|
12
|
+
.slice(0, limit);
|
|
13
|
+
}
|
|
14
|
+
async insert(_args) { }
|
|
15
|
+
async insertBatch(_args) { }
|
|
16
|
+
async delete(_args) { }
|
|
17
|
+
async search(args) {
|
|
18
|
+
const column = args.kind === "tags" ? "tags_vector" : "vector";
|
|
19
|
+
const rows = args.db
|
|
20
|
+
.prepare(`SELECT id, ${column} FROM memories WHERE ${column} IS NOT NULL`)
|
|
21
|
+
.all();
|
|
22
|
+
if (rows.length === 0) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const rankedRows = rows
|
|
26
|
+
.map((row) => ({
|
|
27
|
+
id: row.id,
|
|
28
|
+
vector: this.decodeVector(args.kind === "tags" ? row.tags_vector : row.vector),
|
|
29
|
+
}))
|
|
30
|
+
.filter((row) => row.vector.length > 0);
|
|
31
|
+
return this.rankVectors(rankedRows, args.queryVector, args.limit);
|
|
32
|
+
}
|
|
33
|
+
async rebuildFromShard(_args) { }
|
|
34
|
+
async deleteShardIndexes(_args) { }
|
|
35
|
+
decodeVector(value) {
|
|
36
|
+
if (!value) {
|
|
37
|
+
return new Float32Array();
|
|
38
|
+
}
|
|
39
|
+
if (value instanceof Uint8Array) {
|
|
40
|
+
return new Float32Array(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
|
|
41
|
+
}
|
|
42
|
+
return new Float32Array(value);
|
|
43
|
+
}
|
|
44
|
+
cosineSimilarity(a, b) {
|
|
45
|
+
if (a.length !== b.length) {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
let dot = 0;
|
|
49
|
+
let magA = 0;
|
|
50
|
+
let magB = 0;
|
|
51
|
+
for (let i = 0; i < a.length; i++) {
|
|
52
|
+
const av = a[i] ?? 0;
|
|
53
|
+
const bv = b[i] ?? 0;
|
|
54
|
+
dot += av * bv;
|
|
55
|
+
magA += av * av;
|
|
56
|
+
magB += bv * bv;
|
|
57
|
+
}
|
|
58
|
+
if (magA === 0 || magB === 0) {
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ShardInfo } from "../sqlite/types.js";
|
|
2
|
+
export type VectorKind = "content" | "tags";
|
|
3
|
+
export interface BackendSearchResult {
|
|
4
|
+
id: string;
|
|
5
|
+
distance: number;
|
|
6
|
+
}
|
|
7
|
+
export interface BackendInsertItem {
|
|
8
|
+
id: string;
|
|
9
|
+
vector: Float32Array;
|
|
10
|
+
}
|
|
11
|
+
export interface VectorBackendSearchParams {
|
|
12
|
+
db: unknown;
|
|
13
|
+
shard: ShardInfo;
|
|
14
|
+
kind: VectorKind;
|
|
15
|
+
queryVector: Float32Array;
|
|
16
|
+
limit: number;
|
|
17
|
+
}
|
|
18
|
+
export interface VectorBackend {
|
|
19
|
+
getBackendName(): string;
|
|
20
|
+
insert(args: {
|
|
21
|
+
id: string;
|
|
22
|
+
vector: Float32Array;
|
|
23
|
+
shard: ShardInfo;
|
|
24
|
+
kind: VectorKind;
|
|
25
|
+
}): Promise<void>;
|
|
26
|
+
insertBatch(args: {
|
|
27
|
+
items: BackendInsertItem[];
|
|
28
|
+
shard: ShardInfo;
|
|
29
|
+
kind: VectorKind;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
delete(args: {
|
|
32
|
+
id: string;
|
|
33
|
+
shard: ShardInfo;
|
|
34
|
+
kind: VectorKind;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
search(args: VectorBackendSearchParams): Promise<BackendSearchResult[]>;
|
|
37
|
+
rebuildFromShard(args: {
|
|
38
|
+
db: unknown;
|
|
39
|
+
shard: ShardInfo;
|
|
40
|
+
kind: VectorKind;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
deleteShardIndexes(args: {
|
|
43
|
+
shard: ShardInfo;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
export interface VectorBackendFactoryOptions {
|
|
47
|
+
vectorBackend: "usearch-first" | "usearch" | "exact-scan";
|
|
48
|
+
probeUSearch?: () => Promise<boolean>;
|
|
49
|
+
createUSearchBackend?: () => VectorBackend;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/vector-backends/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,YAAY,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,IAAI,MAAM,CAAC;IACzB,MAAM,CAAC,IAAI,EAAE;QACX,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,YAAY,CAAC;QACrB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,WAAW,CAAC,IAAI,EAAE;QAChB,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAC3B,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClB,MAAM,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,MAAM,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACxE,gBAAgB,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F,kBAAkB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,2BAA2B;IAC1C,aAAa,EAAE,eAAe,GAAG,SAAS,GAAG,YAAY,CAAC;IAC1D,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,aAAa,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { BackendInsertItem, BackendSearchResult, VectorBackend, VectorBackendSearchParams, VectorKind } from "./types.js";
|
|
2
|
+
import type { ShardInfo } from "../sqlite/types.js";
|
|
3
|
+
export declare class USearchBackend implements VectorBackend {
|
|
4
|
+
private readonly options;
|
|
5
|
+
private readonly indexes;
|
|
6
|
+
constructor(options: {
|
|
7
|
+
baseDir: string;
|
|
8
|
+
dimensions: number;
|
|
9
|
+
});
|
|
10
|
+
getBackendName(): string;
|
|
11
|
+
insert(args: {
|
|
12
|
+
id: string;
|
|
13
|
+
vector: Float32Array;
|
|
14
|
+
shard: ShardInfo;
|
|
15
|
+
kind: VectorKind;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
insertBatch(args: {
|
|
18
|
+
items: BackendInsertItem[];
|
|
19
|
+
shard: ShardInfo;
|
|
20
|
+
kind: VectorKind;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
delete(args: {
|
|
23
|
+
id: string;
|
|
24
|
+
shard: ShardInfo;
|
|
25
|
+
kind: VectorKind;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
search(args: VectorBackendSearchParams): Promise<BackendSearchResult[]>;
|
|
28
|
+
rebuildFromShard(args: {
|
|
29
|
+
db: unknown;
|
|
30
|
+
shard: ShardInfo;
|
|
31
|
+
kind: VectorKind;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
deleteShardIndexes(args: {
|
|
34
|
+
shard: ShardInfo;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
insertManyForTest(indexKey: string, items: BackendInsertItem[]): Promise<void>;
|
|
37
|
+
searchForTest(indexKey: string, queryVector: Float32Array, limit: number): Promise<BackendSearchResult[]>;
|
|
38
|
+
private getOrCreateIndex;
|
|
39
|
+
private createEmptyIndex;
|
|
40
|
+
private ensureKey;
|
|
41
|
+
private addItems;
|
|
42
|
+
private upsertItem;
|
|
43
|
+
private decodeVector;
|
|
44
|
+
private getIndexKey;
|
|
45
|
+
private loadUSearch;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=usearch-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usearch-backend.d.ts","sourceRoot":"","sources":["../../../src/services/vector-backends/usearch-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,yBAAyB,EACzB,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAcpD,qBAAa,cAAe,YAAW,aAAa;IAIhD,OAAO,CAAC,QAAQ,CAAC,OAAO;IAH1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;gBAGvC,OAAO,EAAE;QACxB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB;IAKH,cAAc,IAAI,MAAM;IAIlB,MAAM,CAAC,IAAI,EAAE;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,YAAY,CAAC;QACrB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWX,WAAW,CAAC,IAAI,EAAE;QACtB,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAC3B,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;KAClB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWX,MAAM,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/E,MAAM,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAsBvE,gBAAgB,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAmC1F,kBAAkB,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9E,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,YAAY,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAqBnB,gBAAgB;YAShB,gBAAgB;IAY9B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,WAAW;YAIL,WAAW;CAO1B"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export class USearchBackend {
|
|
2
|
+
options;
|
|
3
|
+
indexes = new Map();
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
void this.options.baseDir;
|
|
7
|
+
}
|
|
8
|
+
getBackendName() {
|
|
9
|
+
return "usearch";
|
|
10
|
+
}
|
|
11
|
+
async insert(args) {
|
|
12
|
+
const indexKey = this.getIndexKey(args.shard, args.kind);
|
|
13
|
+
const cache = await this.getOrCreateIndex(indexKey);
|
|
14
|
+
try {
|
|
15
|
+
this.upsertItem(cache, { id: args.id, vector: args.vector });
|
|
16
|
+
cache.initialized = true;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw new Error(`USearch insert failed for ${indexKey}: ${String(error)}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async insertBatch(args) {
|
|
23
|
+
const indexKey = this.getIndexKey(args.shard, args.kind);
|
|
24
|
+
const cache = await this.getOrCreateIndex(indexKey);
|
|
25
|
+
try {
|
|
26
|
+
this.addItems(cache, args.items);
|
|
27
|
+
cache.initialized = true;
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`USearch batch insert failed for ${indexKey}: ${String(error)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async delete(args) {
|
|
34
|
+
const cache = await this.getOrCreateIndex(this.getIndexKey(args.shard, args.kind));
|
|
35
|
+
const key = cache.idToKey.get(args.id);
|
|
36
|
+
if (key === undefined)
|
|
37
|
+
return;
|
|
38
|
+
cache.index.remove(key);
|
|
39
|
+
cache.idToKey.delete(args.id);
|
|
40
|
+
cache.keyToId.delete(key);
|
|
41
|
+
}
|
|
42
|
+
async search(args) {
|
|
43
|
+
const indexKey = this.getIndexKey(args.shard, args.kind);
|
|
44
|
+
const cache = await this.getOrCreateIndex(indexKey);
|
|
45
|
+
try {
|
|
46
|
+
const matches = cache.index.search(args.queryVector, args.limit);
|
|
47
|
+
return Array.from(matches.keys, (key, index) => {
|
|
48
|
+
const id = cache.keyToId.get(key);
|
|
49
|
+
if (!id) {
|
|
50
|
+
throw new Error(`USearch index metadata missing for key ${String(key)} in ${cache.indexKey}`);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
id,
|
|
54
|
+
distance: matches.distances[index] ?? 0,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new Error(`USearch search failed for ${indexKey}: ${String(error)}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async rebuildFromShard(args) {
|
|
63
|
+
const indexKey = this.getIndexKey(args.shard, args.kind);
|
|
64
|
+
const existing = this.indexes.get(indexKey);
|
|
65
|
+
if (existing?.initialized) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const column = args.kind === "tags" ? "tags_vector" : "vector";
|
|
69
|
+
const rows = args.db
|
|
70
|
+
.prepare(`SELECT id, ${column} FROM memories WHERE ${column} IS NOT NULL`)
|
|
71
|
+
.all();
|
|
72
|
+
const cache = await this.createEmptyIndex(indexKey);
|
|
73
|
+
this.indexes.set(indexKey, cache);
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const raw = args.kind === "tags" ? row.tags_vector : row.vector;
|
|
76
|
+
const vector = this.decodeVector(raw);
|
|
77
|
+
if (vector.length === 0)
|
|
78
|
+
continue;
|
|
79
|
+
this.upsertItem(cache, { id: row.id, vector });
|
|
80
|
+
}
|
|
81
|
+
cache.initialized = true;
|
|
82
|
+
}
|
|
83
|
+
async deleteShardIndexes(args) {
|
|
84
|
+
for (const kind of ["content", "tags"]) {
|
|
85
|
+
const indexKey = this.getIndexKey(args.shard, kind);
|
|
86
|
+
this.indexes.delete(indexKey);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async insertManyForTest(indexKey, items) {
|
|
90
|
+
const cache = await this.getOrCreateIndex(indexKey);
|
|
91
|
+
this.addItems(cache, items);
|
|
92
|
+
cache.initialized = true;
|
|
93
|
+
}
|
|
94
|
+
async searchForTest(indexKey, queryVector, limit) {
|
|
95
|
+
const cache = await this.getOrCreateIndex(indexKey);
|
|
96
|
+
try {
|
|
97
|
+
const matches = cache.index.search(queryVector, limit);
|
|
98
|
+
return Array.from(matches.keys, (key, index) => {
|
|
99
|
+
const id = cache.keyToId.get(key);
|
|
100
|
+
if (!id) {
|
|
101
|
+
throw new Error(`USearch index metadata missing for key ${String(key)} in ${cache.indexKey}`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
id,
|
|
105
|
+
distance: matches.distances[index] ?? 0,
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
throw new Error(`USearch test search failed for ${indexKey}: ${String(error)}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async getOrCreateIndex(indexKey) {
|
|
114
|
+
const existing = this.indexes.get(indexKey);
|
|
115
|
+
if (existing)
|
|
116
|
+
return existing;
|
|
117
|
+
const cache = await this.createEmptyIndex(indexKey);
|
|
118
|
+
this.indexes.set(indexKey, cache);
|
|
119
|
+
return cache;
|
|
120
|
+
}
|
|
121
|
+
async createEmptyIndex(indexKey) {
|
|
122
|
+
const usearch = await this.loadUSearch();
|
|
123
|
+
return {
|
|
124
|
+
index: new usearch.Index({ dimensions: this.options.dimensions, metric: "cos" }),
|
|
125
|
+
idToKey: new Map(),
|
|
126
|
+
keyToId: new Map(),
|
|
127
|
+
nextKey: 1n,
|
|
128
|
+
indexKey,
|
|
129
|
+
initialized: false,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
ensureKey(cache, id) {
|
|
133
|
+
const existing = cache.idToKey.get(id);
|
|
134
|
+
if (existing !== undefined)
|
|
135
|
+
return existing;
|
|
136
|
+
const key = cache.nextKey;
|
|
137
|
+
cache.nextKey += 1n;
|
|
138
|
+
cache.idToKey.set(id, key);
|
|
139
|
+
cache.keyToId.set(key, id);
|
|
140
|
+
return key;
|
|
141
|
+
}
|
|
142
|
+
addItems(cache, items) {
|
|
143
|
+
for (const item of items) {
|
|
144
|
+
this.upsertItem(cache, item);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
upsertItem(cache, item) {
|
|
148
|
+
const existing = cache.idToKey.get(item.id);
|
|
149
|
+
if (existing !== undefined) {
|
|
150
|
+
cache.index.remove(existing);
|
|
151
|
+
}
|
|
152
|
+
const key = this.ensureKey(cache, item.id);
|
|
153
|
+
cache.index.add(key, item.vector);
|
|
154
|
+
}
|
|
155
|
+
decodeVector(value) {
|
|
156
|
+
if (!value)
|
|
157
|
+
return new Float32Array();
|
|
158
|
+
if (value instanceof Uint8Array) {
|
|
159
|
+
return new Float32Array(value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength));
|
|
160
|
+
}
|
|
161
|
+
return new Float32Array(value);
|
|
162
|
+
}
|
|
163
|
+
getIndexKey(shard, kind) {
|
|
164
|
+
return `${shard.scope}_${shard.scopeHash}_${shard.shardIndex}_${kind}`;
|
|
165
|
+
}
|
|
166
|
+
async loadUSearch() {
|
|
167
|
+
try {
|
|
168
|
+
return await import("usearch");
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
throw new Error(`Failed to load usearch backend: ${String(error)}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-server-worker.d.ts","sourceRoot":"","sources":["../../src/services/web-server-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { handleListTags, handleListMemories, handleAddMemory, handleDeleteMemory, handleBulkDelete, handleUpdateMemory, handleSearch, handleStats, handlePinMemory, handleUnpinMemory, handleRunCleanup, handleRunDeduplication, handleDetectMigration, handleRunMigration, handleDetectTagMigration, handleRunTagMigrationBatch, handleGetTagMigrationProgress, handleDeletePrompt, handleBulkDeletePrompts, handleGetUserProfile, handleGetProfileChangelog, handleGetProfileSnapshot, handleRefreshProfile, } from "./api-handlers.js";
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = dirname(__filename);
|
|
7
|
+
let server = null;
|
|
8
|
+
async function handleRequest(req) {
|
|
9
|
+
const url = new URL(req.url);
|
|
10
|
+
const path = url.pathname;
|
|
11
|
+
const method = req.method;
|
|
12
|
+
try {
|
|
13
|
+
if (path === "/" || path === "/index.html") {
|
|
14
|
+
return serveStaticFile("index.html", "text/html");
|
|
15
|
+
}
|
|
16
|
+
if (path === "/styles.css") {
|
|
17
|
+
return serveStaticFile("styles.css", "text/css");
|
|
18
|
+
}
|
|
19
|
+
if (path === "/app.js") {
|
|
20
|
+
return serveStaticFile("app.js", "application/javascript");
|
|
21
|
+
}
|
|
22
|
+
if (path === "/favicon.ico") {
|
|
23
|
+
return serveStaticFile("favicon.ico", "image/x-icon");
|
|
24
|
+
}
|
|
25
|
+
if (path === "/api/tags" && method === "GET") {
|
|
26
|
+
const result = await handleListTags();
|
|
27
|
+
return jsonResponse(result);
|
|
28
|
+
}
|
|
29
|
+
if (path === "/api/memories" && method === "GET") {
|
|
30
|
+
const tag = url.searchParams.get("tag") || undefined;
|
|
31
|
+
const page = parseInt(url.searchParams.get("page") || "1");
|
|
32
|
+
const pageSize = parseInt(url.searchParams.get("pageSize") || "20");
|
|
33
|
+
const includePrompts = url.searchParams.get("includePrompts") !== "false";
|
|
34
|
+
const result = await handleListMemories(tag, page, pageSize, includePrompts);
|
|
35
|
+
return jsonResponse(result);
|
|
36
|
+
}
|
|
37
|
+
if (path === "/api/memories" && method === "POST") {
|
|
38
|
+
const body = (await req.json());
|
|
39
|
+
const result = await handleAddMemory(body);
|
|
40
|
+
return jsonResponse(result);
|
|
41
|
+
}
|
|
42
|
+
if (path.startsWith("/api/memories/") && method === "DELETE") {
|
|
43
|
+
const parts = path.split("/");
|
|
44
|
+
const id = parts[3];
|
|
45
|
+
if (!id || id === "bulk-delete") {
|
|
46
|
+
return jsonResponse({ success: false, error: "Invalid ID" });
|
|
47
|
+
}
|
|
48
|
+
const cascade = url.searchParams.get("cascade") === "true";
|
|
49
|
+
const result = await handleDeleteMemory(id, cascade);
|
|
50
|
+
return jsonResponse(result);
|
|
51
|
+
}
|
|
52
|
+
if (path.startsWith("/api/memories/") && method === "PUT") {
|
|
53
|
+
const id = path.split("/").pop();
|
|
54
|
+
if (!id) {
|
|
55
|
+
return jsonResponse({ success: false, error: "Invalid ID" });
|
|
56
|
+
}
|
|
57
|
+
const body = (await req.json());
|
|
58
|
+
const result = await handleUpdateMemory(id, body);
|
|
59
|
+
return jsonResponse(result);
|
|
60
|
+
}
|
|
61
|
+
if (path === "/api/memories/bulk-delete" && method === "POST") {
|
|
62
|
+
const body = (await req.json());
|
|
63
|
+
const cascade = body.cascade !== false;
|
|
64
|
+
const result = await handleBulkDelete(body.ids || [], cascade);
|
|
65
|
+
return jsonResponse(result);
|
|
66
|
+
}
|
|
67
|
+
if (path === "/api/search" && method === "GET") {
|
|
68
|
+
const query = url.searchParams.get("q");
|
|
69
|
+
const tag = url.searchParams.get("tag") || undefined;
|
|
70
|
+
const page = parseInt(url.searchParams.get("page") || "1");
|
|
71
|
+
const pageSize = parseInt(url.searchParams.get("pageSize") || "20");
|
|
72
|
+
if (!query) {
|
|
73
|
+
return jsonResponse({ success: false, error: "query parameter required" });
|
|
74
|
+
}
|
|
75
|
+
const result = await handleSearch(query, tag, page, pageSize);
|
|
76
|
+
return jsonResponse(result);
|
|
77
|
+
}
|
|
78
|
+
if (path === "/api/stats" && method === "GET") {
|
|
79
|
+
const result = await handleStats();
|
|
80
|
+
return jsonResponse(result);
|
|
81
|
+
}
|
|
82
|
+
if (path.match(/^\/api\/memories\/[^/]+\/pin$/) && method === "POST") {
|
|
83
|
+
const id = path.split("/")[3];
|
|
84
|
+
if (!id) {
|
|
85
|
+
return jsonResponse({ success: false, error: "Invalid ID" });
|
|
86
|
+
}
|
|
87
|
+
const result = await handlePinMemory(id);
|
|
88
|
+
return jsonResponse(result);
|
|
89
|
+
}
|
|
90
|
+
if (path.match(/^\/api\/memories\/[^/]+\/unpin$/) && method === "POST") {
|
|
91
|
+
const id = path.split("/")[3];
|
|
92
|
+
if (!id) {
|
|
93
|
+
return jsonResponse({ success: false, error: "Invalid ID" });
|
|
94
|
+
}
|
|
95
|
+
const result = await handleUnpinMemory(id);
|
|
96
|
+
return jsonResponse(result);
|
|
97
|
+
}
|
|
98
|
+
if (path === "/api/cleanup" && method === "POST") {
|
|
99
|
+
const result = await handleRunCleanup();
|
|
100
|
+
return jsonResponse(result);
|
|
101
|
+
}
|
|
102
|
+
if (path === "/api/deduplicate" && method === "POST") {
|
|
103
|
+
const result = await handleRunDeduplication();
|
|
104
|
+
return jsonResponse(result);
|
|
105
|
+
}
|
|
106
|
+
if (path === "/api/migration/detect" && method === "GET") {
|
|
107
|
+
const result = await handleDetectMigration();
|
|
108
|
+
return jsonResponse(result);
|
|
109
|
+
}
|
|
110
|
+
if (path === "/api/migration/tags/detect" && method === "GET") {
|
|
111
|
+
const result = await handleDetectTagMigration();
|
|
112
|
+
return jsonResponse(result);
|
|
113
|
+
}
|
|
114
|
+
if (path === "/api/migration/tags/run-batch" && method === "POST") {
|
|
115
|
+
const body = (await req.json());
|
|
116
|
+
const batchSize = body?.batchSize || 5;
|
|
117
|
+
const result = await handleRunTagMigrationBatch(batchSize);
|
|
118
|
+
return jsonResponse(result);
|
|
119
|
+
}
|
|
120
|
+
if (path === "/api/migration/tags/progress" && method === "GET") {
|
|
121
|
+
const result = await handleGetTagMigrationProgress();
|
|
122
|
+
return jsonResponse(result);
|
|
123
|
+
}
|
|
124
|
+
if (path === "/api/migration/run" && method === "POST") {
|
|
125
|
+
const body = (await req.json());
|
|
126
|
+
const strategy = body.strategy || "fresh-start";
|
|
127
|
+
if (strategy !== "fresh-start" && strategy !== "re-embed") {
|
|
128
|
+
return jsonResponse({ success: false, error: "Invalid strategy" });
|
|
129
|
+
}
|
|
130
|
+
const result = await handleRunMigration(strategy);
|
|
131
|
+
return jsonResponse(result);
|
|
132
|
+
}
|
|
133
|
+
if (path.startsWith("/api/prompts/") && method === "DELETE") {
|
|
134
|
+
const parts = path.split("/");
|
|
135
|
+
const id = parts[3];
|
|
136
|
+
if (!id || id === "bulk-delete") {
|
|
137
|
+
return jsonResponse({ success: false, error: "Invalid ID" });
|
|
138
|
+
}
|
|
139
|
+
const cascade = url.searchParams.get("cascade") === "true";
|
|
140
|
+
const result = await handleDeletePrompt(id, cascade);
|
|
141
|
+
return jsonResponse(result);
|
|
142
|
+
}
|
|
143
|
+
if (path === "/api/prompts/bulk-delete" && method === "POST") {
|
|
144
|
+
const body = (await req.json());
|
|
145
|
+
const cascade = body.cascade !== false;
|
|
146
|
+
const result = await handleBulkDeletePrompts(body.ids || [], cascade);
|
|
147
|
+
return jsonResponse(result);
|
|
148
|
+
}
|
|
149
|
+
if (path === "/api/user-profile" && method === "GET") {
|
|
150
|
+
const userId = url.searchParams.get("userId") || undefined;
|
|
151
|
+
const result = await handleGetUserProfile(userId);
|
|
152
|
+
return jsonResponse(result);
|
|
153
|
+
}
|
|
154
|
+
if (path === "/api/user-profile/changelog" && method === "GET") {
|
|
155
|
+
const profileId = url.searchParams.get("profileId");
|
|
156
|
+
const limit = parseInt(url.searchParams.get("limit") || "5");
|
|
157
|
+
if (!profileId) {
|
|
158
|
+
return jsonResponse({ success: false, error: "profileId parameter required" });
|
|
159
|
+
}
|
|
160
|
+
const result = await handleGetProfileChangelog(profileId, limit);
|
|
161
|
+
return jsonResponse(result);
|
|
162
|
+
}
|
|
163
|
+
if (path === "/api/user-profile/snapshot" && method === "GET") {
|
|
164
|
+
const changelogId = url.searchParams.get("chlogId");
|
|
165
|
+
if (!changelogId) {
|
|
166
|
+
return jsonResponse({ success: false, error: "changelogId parameter required" });
|
|
167
|
+
}
|
|
168
|
+
const result = await handleGetProfileSnapshot(changelogId);
|
|
169
|
+
return jsonResponse(result);
|
|
170
|
+
}
|
|
171
|
+
if (path === "/api/user-profile/refresh" && method === "POST") {
|
|
172
|
+
const body = (await req.json().catch(() => ({})));
|
|
173
|
+
const userId = body.userId || undefined;
|
|
174
|
+
const result = await handleRefreshProfile(userId);
|
|
175
|
+
return jsonResponse(result);
|
|
176
|
+
}
|
|
177
|
+
return new Response("Not Found", { status: 404 });
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return jsonResponse({
|
|
181
|
+
success: false,
|
|
182
|
+
error: String(error),
|
|
183
|
+
}, 500);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function serveStaticFile(filename, contentType) {
|
|
187
|
+
try {
|
|
188
|
+
const webDir = join(__dirname, "..", "web");
|
|
189
|
+
const filePath = join(webDir, filename);
|
|
190
|
+
if (contentType.startsWith("image/")) {
|
|
191
|
+
const content = readFileSync(filePath);
|
|
192
|
+
return new Response(content, {
|
|
193
|
+
headers: {
|
|
194
|
+
"Content-Type": contentType,
|
|
195
|
+
"Cache-Control": "public, max-age=86400",
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
const content = readFileSync(filePath, "utf-8");
|
|
200
|
+
return new Response(content, {
|
|
201
|
+
headers: {
|
|
202
|
+
"Content-Type": contentType,
|
|
203
|
+
"Cache-Control": "no-cache",
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
return new Response("File not found", { status: 404 });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function jsonResponse(data, status = 200) {
|
|
212
|
+
return new Response(JSON.stringify(data), {
|
|
213
|
+
status,
|
|
214
|
+
headers: {
|
|
215
|
+
"Content-Type": "application/json",
|
|
216
|
+
"Access-Control-Allow-Origin": "*",
|
|
217
|
+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
|
218
|
+
"Access-Control-Allow-Headers": "Content-Type",
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
self.onmessage = async (event) => {
|
|
223
|
+
const message = event.data;
|
|
224
|
+
try {
|
|
225
|
+
switch (message.type) {
|
|
226
|
+
case "start": {
|
|
227
|
+
if (server) {
|
|
228
|
+
self.postMessage({
|
|
229
|
+
type: "error",
|
|
230
|
+
error: "Server already running",
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
server = Bun.serve({
|
|
235
|
+
port: message.port,
|
|
236
|
+
hostname: message.host,
|
|
237
|
+
fetch: handleRequest,
|
|
238
|
+
});
|
|
239
|
+
self.postMessage({
|
|
240
|
+
type: "started",
|
|
241
|
+
url: `http://${message.host}:${message.port}`,
|
|
242
|
+
});
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
case "stop": {
|
|
246
|
+
if (server) {
|
|
247
|
+
server.stop();
|
|
248
|
+
server = null;
|
|
249
|
+
self.postMessage({
|
|
250
|
+
type: "stopped",
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
self.postMessage({
|
|
255
|
+
type: "error",
|
|
256
|
+
error: "Server not running",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case "status": {
|
|
262
|
+
self.postMessage({
|
|
263
|
+
type: "status",
|
|
264
|
+
running: server !== null,
|
|
265
|
+
});
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
default: {
|
|
269
|
+
self.postMessage({
|
|
270
|
+
type: "error",
|
|
271
|
+
error: `Unknown message type: ${message.type}`,
|
|
272
|
+
});
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
self.postMessage({
|
|
279
|
+
type: "error",
|
|
280
|
+
error: String(error),
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
interface WebServerConfig {
|
|
2
|
+
port: number;
|
|
3
|
+
host: string;
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare class WebServer {
|
|
7
|
+
private server;
|
|
8
|
+
private config;
|
|
9
|
+
private isOwner;
|
|
10
|
+
private startPromise;
|
|
11
|
+
private healthCheckInterval;
|
|
12
|
+
private onTakeoverCallback;
|
|
13
|
+
constructor(config: WebServerConfig);
|
|
14
|
+
setOnTakeoverCallback(callback: () => Promise<void>): void;
|
|
15
|
+
start(): Promise<void>;
|
|
16
|
+
private _start;
|
|
17
|
+
private startHealthCheckLoop;
|
|
18
|
+
private stopHealthCheckLoop;
|
|
19
|
+
private attemptTakeover;
|
|
20
|
+
stop(): Promise<void>;
|
|
21
|
+
isRunning(): boolean;
|
|
22
|
+
isServerOwner(): boolean;
|
|
23
|
+
getUrl(): string;
|
|
24
|
+
checkServerAvailable(): Promise<boolean>;
|
|
25
|
+
private handleRequest;
|
|
26
|
+
private serveStaticFile;
|
|
27
|
+
private jsonResponse;
|
|
28
|
+
}
|
|
29
|
+
export declare function startWebServer(config: WebServerConfig): Promise<WebServer>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=web-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-server.d.ts","sourceRoot":"","sources":["../../src/services/web-server.ts"],"names":[],"mappings":"AAiCA,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,mBAAmB,CAA+B;IAC1D,OAAO,CAAC,kBAAkB,CAAsC;gBAEpD,MAAM,EAAE,eAAe;IAInC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YASd,MAAM;IAgCpB,OAAO,CAAC,oBAAoB;IAe5B,OAAO,CAAC,mBAAmB;YAOb,eAAe;IA+BvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,SAAS,IAAI,OAAO;IAIpB,aAAa,IAAI,OAAO;IAIxB,MAAM,IAAI,MAAM;IAIV,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC;YAchC,aAAa;IAuN3B,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,YAAY;CAWrB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAIhF"}
|