@agentdocstore/core 0.2.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 +55 -0
- package/dist/authz.d.ts +76 -0
- package/dist/authz.js +106 -0
- package/dist/diff.d.ts +31 -0
- package/dist/diff.js +57 -0
- package/dist/errors.d.ts +54 -0
- package/dist/errors.js +75 -0
- package/dist/id.d.ts +18 -0
- package/dist/id.js +26 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +15 -0
- package/dist/model/comment.d.ts +18 -0
- package/dist/model/comment.js +2 -0
- package/dist/model/document.d.ts +41 -0
- package/dist/model/document.js +32 -0
- package/dist/model/edit-message.d.ts +8 -0
- package/dist/model/edit-message.js +20 -0
- package/dist/model/limits.d.ts +42 -0
- package/dist/model/limits.js +43 -0
- package/dist/model/title.d.ts +8 -0
- package/dist/model/title.js +17 -0
- package/dist/model/version.d.ts +20 -0
- package/dist/model/version.js +2 -0
- package/dist/offline.d.ts +57 -0
- package/dist/offline.js +58 -0
- package/dist/scanner.d.ts +47 -0
- package/dist/scanner.js +294 -0
- package/dist/search/CoreSearchIndex.d.ts +21 -0
- package/dist/search/CoreSearchIndex.js +87 -0
- package/dist/spi/capabilities.d.ts +28 -0
- package/dist/spi/capabilities.js +2 -0
- package/dist/spi/comments.d.ts +14 -0
- package/dist/spi/comments.js +2 -0
- package/dist/spi/identity.d.ts +13 -0
- package/dist/spi/identity.js +2 -0
- package/dist/spi/index.d.ts +8 -0
- package/dist/spi/index.js +8 -0
- package/dist/spi/module.d.ts +54 -0
- package/dist/spi/module.js +57 -0
- package/dist/spi/provider.d.ts +33 -0
- package/dist/spi/provider.js +2 -0
- package/dist/spi/repository.d.ts +64 -0
- package/dist/spi/repository.js +2 -0
- package/dist/spi/search.d.ts +53 -0
- package/dist/spi/search.js +2 -0
- package/package.json +58 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import MiniSearch from 'minisearch';
|
|
2
|
+
const SEARCH_FIELDS = ['title', 'content'];
|
|
3
|
+
const STORE_FIELDS = ['owner', 'visibility', 'expiresAt'];
|
|
4
|
+
const OPTIONS = {
|
|
5
|
+
idField: 'id',
|
|
6
|
+
fields: SEARCH_FIELDS,
|
|
7
|
+
storeFields: STORE_FIELDS,
|
|
8
|
+
searchOptions: { prefix: true, fuzzy: 0.2, combineWith: 'AND' },
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The default {@link SearchIndex} implementation, backed by MiniSearch. Used by
|
|
12
|
+
* any provider whose {@link Capabilities.search} is `'core-fallback'`.
|
|
13
|
+
*
|
|
14
|
+
* `query` returns PUBLIC hits plus the viewer's own PRIVATE hits — a PRIVATE
|
|
15
|
+
* doc owned by someone else is never returned.
|
|
16
|
+
*/
|
|
17
|
+
export class CoreSearchIndex {
|
|
18
|
+
mini;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.mini = new MiniSearch(OPTIONS);
|
|
21
|
+
}
|
|
22
|
+
add(doc) {
|
|
23
|
+
// Idempotent: replace any prior doc with the same id.
|
|
24
|
+
if (this.mini.has(doc.documentId))
|
|
25
|
+
this.mini.discard(doc.documentId);
|
|
26
|
+
this.mini.add(toIndexed(doc));
|
|
27
|
+
}
|
|
28
|
+
update(doc) {
|
|
29
|
+
this.add(doc);
|
|
30
|
+
}
|
|
31
|
+
remove(documentId) {
|
|
32
|
+
if (this.mini.has(documentId))
|
|
33
|
+
this.mini.discard(documentId);
|
|
34
|
+
}
|
|
35
|
+
query(q, viewer, opts) {
|
|
36
|
+
const trimmed = q.trim();
|
|
37
|
+
if (trimmed.length > 0 && this.mini.dirtCount > 0) {
|
|
38
|
+
// Replacing or removing a document only marks its old entry as
|
|
39
|
+
// discarded; MiniSearch drops those entries later, or when a search
|
|
40
|
+
// meets them. A search that meets one scores the matches it saw before
|
|
41
|
+
// it as if the discarded entry still counted, which can make scores
|
|
42
|
+
// negative and put a weaker match first. This throwaway search drops
|
|
43
|
+
// the discarded entries for these terms, so the one below scores right.
|
|
44
|
+
this.mini.search(trimmed);
|
|
45
|
+
}
|
|
46
|
+
const raw = trimmed.length === 0 ? [] : this.mini.search(trimmed);
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
const visible = raw.filter((r) => {
|
|
49
|
+
const visibility = r['visibility'];
|
|
50
|
+
const owner = r['owner'];
|
|
51
|
+
const expiresAt = r['expiresAt'];
|
|
52
|
+
if (expiresAt !== undefined && Date.parse(expiresAt) <= now)
|
|
53
|
+
return false;
|
|
54
|
+
return visibility === 'PUBLIC' || (viewer !== null && owner === viewer);
|
|
55
|
+
});
|
|
56
|
+
const total = visible.length;
|
|
57
|
+
const offset = opts?.offset ?? 0;
|
|
58
|
+
const limit = opts?.limit ?? 50;
|
|
59
|
+
const hits = visible
|
|
60
|
+
.slice(offset, offset + limit)
|
|
61
|
+
.map((r) => ({ documentId: String(r.id), score: r.score }));
|
|
62
|
+
return { hits, total };
|
|
63
|
+
}
|
|
64
|
+
snapshot() {
|
|
65
|
+
return JSON.stringify(this.mini);
|
|
66
|
+
}
|
|
67
|
+
restore(snapshot) {
|
|
68
|
+
this.mini = MiniSearch.loadJSON(snapshot, OPTIONS);
|
|
69
|
+
}
|
|
70
|
+
clear() {
|
|
71
|
+
this.mini = new MiniSearch(OPTIONS);
|
|
72
|
+
}
|
|
73
|
+
size() {
|
|
74
|
+
return this.mini.documentCount;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function toIndexed(doc) {
|
|
78
|
+
return {
|
|
79
|
+
id: doc.documentId,
|
|
80
|
+
owner: doc.owner,
|
|
81
|
+
visibility: doc.visibility,
|
|
82
|
+
title: doc.title,
|
|
83
|
+
content: doc.content,
|
|
84
|
+
...(doc.expiresAt !== undefined ? { expiresAt: doc.expiresAt } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=CoreSearchIndex.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** How a provider satisfies search. */
|
|
2
|
+
export type SearchCapability =
|
|
3
|
+
/** Provider has no native search; the core MiniSearch fallback is used. */
|
|
4
|
+
'core-fallback'
|
|
5
|
+
/** Provider implements search natively (e.g. a database full-text index). */
|
|
6
|
+
| 'native';
|
|
7
|
+
/** Static description of what a {@link Provider} supports. */
|
|
8
|
+
export interface Capabilities {
|
|
9
|
+
/** Search strategy this provider uses. */
|
|
10
|
+
readonly search: SearchCapability;
|
|
11
|
+
/** True if the store expires documents itself; false means the server must sweep. */
|
|
12
|
+
readonly nativeTtl: boolean;
|
|
13
|
+
/** True if version appends are committed atomically (content-before-pointer). */
|
|
14
|
+
readonly atomicVersioning: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* True if this provider talks to anything off-box (a database, an object
|
|
17
|
+
* store, a remote API). Providers MUST declare this honestly: offline mode
|
|
18
|
+
* refuses to start when a provider reports `true`, and the network fuse would
|
|
19
|
+
* sever its connections anyway. Only a provider that is entirely local —
|
|
20
|
+
* in-process memory, or files on this machine — may report `false`.
|
|
21
|
+
*
|
|
22
|
+
* A unix-domain socket to a local daemon still counts as `true`: the fuse
|
|
23
|
+
* permits unix sockets, but the operator deserves to know the store is not
|
|
24
|
+
* self-contained.
|
|
25
|
+
*/
|
|
26
|
+
readonly requiresNetwork: boolean;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Comment } from '../model/comment.js';
|
|
2
|
+
/** Input to add a comment. */
|
|
3
|
+
export interface AddCommentInput {
|
|
4
|
+
readonly author: string;
|
|
5
|
+
readonly body: string;
|
|
6
|
+
}
|
|
7
|
+
/** Storage of per-doc comments. */
|
|
8
|
+
export interface CommentStore {
|
|
9
|
+
add(documentId: string, input: AddCommentInput): Promise<Comment>;
|
|
10
|
+
list(documentId: string): Promise<readonly Comment[]>;
|
|
11
|
+
setResolved(documentId: string, commentId: string, resolved: boolean): Promise<Comment>;
|
|
12
|
+
delete(documentId: string, commentId: string): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=comments.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** The resolved caller identity. */
|
|
2
|
+
export interface Identity {
|
|
3
|
+
/** The authenticated user, or the configured single-user default. */
|
|
4
|
+
readonly user: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the caller identity from request headers. Implementations are
|
|
8
|
+
* selected by server auth mode (single-user / trusted-header / token).
|
|
9
|
+
*/
|
|
10
|
+
export interface IdentityProvider {
|
|
11
|
+
identify(headers: Readonly<Record<string, string | undefined>>): Identity | Promise<Identity>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './capabilities.js';
|
|
2
|
+
export * from './repository.js';
|
|
3
|
+
export * from './comments.js';
|
|
4
|
+
export * from './search.js';
|
|
5
|
+
export * from './identity.js';
|
|
6
|
+
export * from './provider.js';
|
|
7
|
+
export * from './module.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './capabilities.js';
|
|
2
|
+
export * from './repository.js';
|
|
3
|
+
export * from './comments.js';
|
|
4
|
+
export * from './search.js';
|
|
5
|
+
export * from './identity.js';
|
|
6
|
+
export * from './provider.js';
|
|
7
|
+
export * from './module.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The loading contract for a third-party storage backend.
|
|
3
|
+
*
|
|
4
|
+
* A provider ships as an ordinary npm package that the operator installs next
|
|
5
|
+
* to AgentDocStore and names in configuration:
|
|
6
|
+
*
|
|
7
|
+
* ```json
|
|
8
|
+
* { "provider": { "module": "@acme/agentdocstore-provider-postgres",
|
|
9
|
+
* "options": { "url": "postgres://localhost/agentdocstore" } } }
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The package's entry point must satisfy {@link ProviderModule}. It is resolved
|
|
13
|
+
* from the operator's working directory, NOT from AgentDocStore's own
|
|
14
|
+
* `node_modules`, so no fork of this repository is required to add a store.
|
|
15
|
+
*/
|
|
16
|
+
import type { Provider } from './provider.js';
|
|
17
|
+
/**
|
|
18
|
+
* The subset of a schema object the loader needs. Zod's `ZodType` satisfies
|
|
19
|
+
* this structurally, so a provider may export a zod schema without core taking
|
|
20
|
+
* a dependency on zod.
|
|
21
|
+
*/
|
|
22
|
+
export interface OptionsSchema {
|
|
23
|
+
/** Return the validated options, or throw to reject them. */
|
|
24
|
+
parse(input: unknown): unknown;
|
|
25
|
+
}
|
|
26
|
+
/** The shape a provider package's entry point must export. */
|
|
27
|
+
export interface ProviderModule {
|
|
28
|
+
/**
|
|
29
|
+
* Human-readable name, reported at boot and by `agentdocstore doctor`. Use the
|
|
30
|
+
* store, not the package: `postgres`, `dynamodb`, `s3`.
|
|
31
|
+
*/
|
|
32
|
+
readonly providerName: string;
|
|
33
|
+
/**
|
|
34
|
+
* Optional validator for this provider's `options` block. Supply one: it
|
|
35
|
+
* turns a mistyped connection string into a readable boot failure instead of
|
|
36
|
+
* a 500 on first write.
|
|
37
|
+
*/
|
|
38
|
+
readonly optionsSchema?: OptionsSchema;
|
|
39
|
+
/**
|
|
40
|
+
* Construct the provider. Any connection, migration, or handshake work
|
|
41
|
+
* belongs here — a returned provider is expected to be ready to serve.
|
|
42
|
+
* Throwing aborts startup with the message shown to the operator.
|
|
43
|
+
*/
|
|
44
|
+
createProvider(options: unknown): Promise<Provider>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Runtime shape check for a dynamically imported module. Kept in core so the
|
|
48
|
+
* CLI, a fork's own host process, and the conformance kit all reject the same
|
|
49
|
+
* malformed modules with the same message.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isProviderModule(value: unknown): value is ProviderModule;
|
|
52
|
+
/** Explains precisely which clause of the contract a module failed. */
|
|
53
|
+
export declare function describeProviderModuleDefect(value: unknown): string;
|
|
54
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The loading contract for a third-party storage backend.
|
|
3
|
+
*
|
|
4
|
+
* A provider ships as an ordinary npm package that the operator installs next
|
|
5
|
+
* to AgentDocStore and names in configuration:
|
|
6
|
+
*
|
|
7
|
+
* ```json
|
|
8
|
+
* { "provider": { "module": "@acme/agentdocstore-provider-postgres",
|
|
9
|
+
* "options": { "url": "postgres://localhost/agentdocstore" } } }
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The package's entry point must satisfy {@link ProviderModule}. It is resolved
|
|
13
|
+
* from the operator's working directory, NOT from AgentDocStore's own
|
|
14
|
+
* `node_modules`, so no fork of this repository is required to add a store.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Runtime shape check for a dynamically imported module. Kept in core so the
|
|
18
|
+
* CLI, a fork's own host process, and the conformance kit all reject the same
|
|
19
|
+
* malformed modules with the same message.
|
|
20
|
+
*/
|
|
21
|
+
export function isProviderModule(value) {
|
|
22
|
+
if (typeof value !== 'object' || value === null)
|
|
23
|
+
return false;
|
|
24
|
+
const m = value;
|
|
25
|
+
if (typeof m.providerName !== 'string' || m.providerName.length === 0)
|
|
26
|
+
return false;
|
|
27
|
+
if (typeof m.createProvider !== 'function')
|
|
28
|
+
return false;
|
|
29
|
+
if (m.optionsSchema !== undefined &&
|
|
30
|
+
(typeof m.optionsSchema !== 'object' ||
|
|
31
|
+
m.optionsSchema === null ||
|
|
32
|
+
typeof m.optionsSchema.parse !== 'function')) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
/** Explains precisely which clause of the contract a module failed. */
|
|
38
|
+
export function describeProviderModuleDefect(value) {
|
|
39
|
+
if (typeof value !== 'object' || value === null) {
|
|
40
|
+
return 'module did not export an object';
|
|
41
|
+
}
|
|
42
|
+
const m = value;
|
|
43
|
+
if (typeof m.providerName !== 'string' || m.providerName.length === 0) {
|
|
44
|
+
return "missing a non-empty 'providerName' export";
|
|
45
|
+
}
|
|
46
|
+
if (typeof m.createProvider !== 'function') {
|
|
47
|
+
return "missing a 'createProvider(options)' export";
|
|
48
|
+
}
|
|
49
|
+
if (m.optionsSchema !== undefined) {
|
|
50
|
+
const s = m.optionsSchema;
|
|
51
|
+
if (typeof s !== 'object' || s === null || typeof s.parse !== 'function') {
|
|
52
|
+
return "'optionsSchema' is present but has no parse() method";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return 'unknown defect';
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DocumentRepository } from './repository.js';
|
|
2
|
+
import type { CommentStore } from './comments.js';
|
|
3
|
+
import type { SearchIndex } from './search.js';
|
|
4
|
+
import type { Capabilities } from './capabilities.js';
|
|
5
|
+
/** Result of an optional provider health probe. */
|
|
6
|
+
export interface ProviderHealth {
|
|
7
|
+
/** False when the backing store is unreachable or refusing work. */
|
|
8
|
+
readonly healthy: boolean;
|
|
9
|
+
/** Short human-readable detail, shown by `/healthz` and `agentdocstore doctor`. */
|
|
10
|
+
readonly detail?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A storage backend: the composition of a repository, comment store, search
|
|
14
|
+
* index, and a static capabilities descriptor. Concrete providers
|
|
15
|
+
* (filesystem, in-memory, or a fork's S3/DDB/Postgres) implement this.
|
|
16
|
+
*/
|
|
17
|
+
export interface Provider {
|
|
18
|
+
readonly repository: DocumentRepository;
|
|
19
|
+
readonly comments: CommentStore;
|
|
20
|
+
readonly search: SearchIndex;
|
|
21
|
+
readonly capabilities: Capabilities;
|
|
22
|
+
/**
|
|
23
|
+
* Optional liveness probe for a store that can be down independently of this
|
|
24
|
+
* process (a database, an object store). Omit it for a local provider whose
|
|
25
|
+
* health is implied by successful construction. When present it is surfaced
|
|
26
|
+
* on `/healthz`, so it MUST be cheap and MUST NOT throw — report
|
|
27
|
+
* `{ healthy: false, detail }` instead.
|
|
28
|
+
*/
|
|
29
|
+
healthCheck?(): Promise<ProviderHealth>;
|
|
30
|
+
/** Release any held resources (locks, file handles, timers). */
|
|
31
|
+
close(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Document, Language, Visibility } from '../model/document.js';
|
|
2
|
+
import type { DocumentVersion } from '../model/version.js';
|
|
3
|
+
/** Input to create a new doc (with its initial version content). */
|
|
4
|
+
export interface CreateDocumentInput {
|
|
5
|
+
readonly title: string;
|
|
6
|
+
readonly language: Language;
|
|
7
|
+
readonly visibility: Visibility;
|
|
8
|
+
/** Initial version-1 content. */
|
|
9
|
+
readonly content: string;
|
|
10
|
+
readonly createdBy: string;
|
|
11
|
+
/** Optional ISO-8601 expiry. */
|
|
12
|
+
readonly expiresAt?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Partial metadata update. `expiresAt: null` clears an existing expiry. */
|
|
15
|
+
export interface UpdateMetaInput {
|
|
16
|
+
readonly title?: string;
|
|
17
|
+
readonly language?: Language;
|
|
18
|
+
readonly expiresAt?: string | null;
|
|
19
|
+
}
|
|
20
|
+
/** Input to append a new immutable version under optimistic concurrency (CAS). */
|
|
21
|
+
export interface AppendVersionInput {
|
|
22
|
+
readonly content: string;
|
|
23
|
+
readonly editedBy: string;
|
|
24
|
+
/** Optional edit note, stored on the new version as `message`. */
|
|
25
|
+
readonly message?: string;
|
|
26
|
+
/** CAS guard: the version the caller believes is current. */
|
|
27
|
+
readonly expect: {
|
|
28
|
+
readonly latestVersion: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** Opaque forward-cursor pagination request. */
|
|
32
|
+
export interface ListQuery {
|
|
33
|
+
readonly limit?: number;
|
|
34
|
+
readonly cursor?: string;
|
|
35
|
+
}
|
|
36
|
+
/** A page of results with an optional continuation cursor. */
|
|
37
|
+
export interface Page<T> {
|
|
38
|
+
readonly items: readonly T[];
|
|
39
|
+
readonly nextCursor?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Storage of documents and their immutable versions.
|
|
43
|
+
*
|
|
44
|
+
* Contract highlights:
|
|
45
|
+
* - `appendVersion` MUST throw {@link VersionConflictError} when
|
|
46
|
+
* `expect.latestVersion` does not match the stored latest (CAS).
|
|
47
|
+
* - Reads for an unknown OR malformed id return `null`/empty rather than throw.
|
|
48
|
+
* - Mutations for an unknown id throw {@link NotFoundError}.
|
|
49
|
+
*/
|
|
50
|
+
export interface DocumentRepository {
|
|
51
|
+
create(input: CreateDocumentInput): Promise<Document>;
|
|
52
|
+
get(id: string): Promise<Document | null>;
|
|
53
|
+
getVersion(id: string, version: number): Promise<DocumentVersion | null>;
|
|
54
|
+
listVersions(id: string): Promise<readonly DocumentVersion[]>;
|
|
55
|
+
appendVersion(id: string, input: AppendVersionInput): Promise<Document>;
|
|
56
|
+
updateMeta(id: string, meta: UpdateMetaInput): Promise<Document>;
|
|
57
|
+
setVisibility(id: string, visibility: Visibility): Promise<Document>;
|
|
58
|
+
delete(id: string): Promise<void>;
|
|
59
|
+
/** List documents owned by `owner`, newest first. */
|
|
60
|
+
listByOwner(owner: string, query?: ListQuery): Promise<Page<Document>>;
|
|
61
|
+
/** Ids of documents whose `expiresAt` is at or before `nowIso` (sweep target). */
|
|
62
|
+
listExpired(nowIso: string, limit: number): Promise<readonly string[]>;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Visibility } from '../model/document.js';
|
|
2
|
+
/** A document indexed for search. */
|
|
3
|
+
export interface SearchDoc {
|
|
4
|
+
readonly documentId: string;
|
|
5
|
+
readonly owner: string;
|
|
6
|
+
readonly visibility: Visibility;
|
|
7
|
+
readonly title: string;
|
|
8
|
+
readonly content: string;
|
|
9
|
+
/**
|
|
10
|
+
* Optional ISO-8601 expiry. An expired entry is excluded from `query` hits
|
|
11
|
+
* and `total` even before the sweep removes it. Optional so existing index
|
|
12
|
+
* writers keep working; they simply get no read-time expiry filtering.
|
|
13
|
+
*/
|
|
14
|
+
readonly expiresAt?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Query pagination options. */
|
|
17
|
+
export interface SearchQueryOptions {
|
|
18
|
+
readonly limit?: number;
|
|
19
|
+
readonly offset?: number;
|
|
20
|
+
}
|
|
21
|
+
/** A single search hit. */
|
|
22
|
+
export interface SearchHit {
|
|
23
|
+
readonly documentId: string;
|
|
24
|
+
readonly score: number;
|
|
25
|
+
}
|
|
26
|
+
/** Search results with the total number of visible matches (pre-pagination). */
|
|
27
|
+
export interface SearchResults {
|
|
28
|
+
readonly hits: readonly SearchHit[];
|
|
29
|
+
readonly total: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Full-text index over documents.
|
|
33
|
+
*
|
|
34
|
+
* `query` MUST enforce visibility: it returns PUBLIC hits plus the `viewer`'s
|
|
35
|
+
* own PRIVATE hits, and nothing else. `snapshot`/`restore` allow a provider to
|
|
36
|
+
* persist and reload the index (filesystem provider persists a snapshot and
|
|
37
|
+
* rebuilds it from the store if the snapshot is missing or corrupt).
|
|
38
|
+
*/
|
|
39
|
+
export interface SearchIndex {
|
|
40
|
+
add(doc: SearchDoc): void;
|
|
41
|
+
update(doc: SearchDoc): void;
|
|
42
|
+
remove(documentId: string): void;
|
|
43
|
+
query(q: string, viewer: string | null, opts?: SearchQueryOptions): SearchResults;
|
|
44
|
+
/** Serialize the whole index to a string. */
|
|
45
|
+
snapshot(): string;
|
|
46
|
+
/** Replace the index contents from a prior {@link snapshot}. */
|
|
47
|
+
restore(snapshot: string): void;
|
|
48
|
+
/** Empty the index. */
|
|
49
|
+
clear(): void;
|
|
50
|
+
/** Number of indexed documents. */
|
|
51
|
+
size(): number;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=search.d.ts.map
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentdocstore/core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "AgentDocStore core: domain model, storage provider SPI, authorization, credential scanner and diff engine.",
|
|
5
|
+
"homepage": "https://github.com/koushikginjupally/agentdocstore/tree/main/packages/core#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/koushikginjupally/agentdocstore/issues"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/koushikginjupally/agentdocstore.git",
|
|
12
|
+
"directory": "packages/core"
|
|
13
|
+
},
|
|
14
|
+
"license": "Apache-2.0",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"!dist/**/*.map"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public",
|
|
30
|
+
"provenance": true
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"agentdocstore",
|
|
37
|
+
"documents",
|
|
38
|
+
"storage-provider",
|
|
39
|
+
"spi"
|
|
40
|
+
],
|
|
41
|
+
"scripts": {
|
|
42
|
+
"clean": "node ../../scripts/clean.mjs packages/core",
|
|
43
|
+
"prebuild": "npm run clean",
|
|
44
|
+
"build": "tsc -p tsconfig.json",
|
|
45
|
+
"prepack": "npm run build",
|
|
46
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"test": "vitest run"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"minisearch": "^7.1.0",
|
|
51
|
+
"nanoid": "^5.0.7",
|
|
52
|
+
"diff": "^9.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"typescript": "^5.6.0",
|
|
56
|
+
"vitest": "^5.0.0"
|
|
57
|
+
}
|
|
58
|
+
}
|