@nacre.work/sdk 0.0.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 +3 -0
- package/dist/client.d.ts +124 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +410 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -0
package/README.md
ADDED
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { CreatedServiceAccount, Document, Grant, GrantInput, IngestOutcome, IngestRequest, Job, Layer, LayerInput, SearchHit, SearchOptions, ServiceAccount } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The TypeScript client.
|
|
4
|
+
*
|
|
5
|
+
* Two decisions shape the whole surface, and both are about the permission
|
|
6
|
+
* model rather than about ergonomics.
|
|
7
|
+
*
|
|
8
|
+
* **No method takes an organization.** Not as an option, not as an override for
|
|
9
|
+
* administrators, not anywhere. Invariant I1 says the organization comes from
|
|
10
|
+
* the token, and the server refuses a request that names one with a 403 — which
|
|
11
|
+
* from inside an application reads as a bug in this library. Making it
|
|
12
|
+
* unrepresentable is cheaper than explaining it.
|
|
13
|
+
*
|
|
14
|
+
* **`get`-shaped methods answer `undefined` for 404 rather than throwing.** The
|
|
15
|
+
* API returns the same 404, with the same wording, for "absent" and for "not
|
|
16
|
+
* yours" (invariant I4). A client that surfaced those as an exception would
|
|
17
|
+
* invite a `catch` that treats one as retryable and the other as fatal, and
|
|
18
|
+
* there is no information here to tell them apart. `undefined` says exactly
|
|
19
|
+
* what the server said.
|
|
20
|
+
*
|
|
21
|
+
* Zero dependencies. `fetch` is in every runtime this targets, and a client for
|
|
22
|
+
* a security product is the wrong place to inherit a dependency tree.
|
|
23
|
+
*/
|
|
24
|
+
export interface ClientOptions {
|
|
25
|
+
/** Where the API lives, e.g. `https://api.nacre.work`. No trailing `/v1`. */
|
|
26
|
+
readonly baseUrl: string;
|
|
27
|
+
/**
|
|
28
|
+
* A JWT from `init`, or a `nacre_sk_` service account key. The client does
|
|
29
|
+
* not care which — both go in the same header, and the server distinguishes
|
|
30
|
+
* them. The organization is inside it, which is why no method takes one.
|
|
31
|
+
*/
|
|
32
|
+
readonly token: string;
|
|
33
|
+
/** Per-request timeout in milliseconds. Default 30 seconds. */
|
|
34
|
+
readonly timeoutMs?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Attempts for a transient failure (429, 503, 5xx). Default 2, meaning one
|
|
37
|
+
* retry. Only ever applied to safe methods and to ingest, which is idempotent
|
|
38
|
+
* on `(layer, external_id)` and its content hash — retrying a delete or a
|
|
39
|
+
* grant would be a second, different write.
|
|
40
|
+
*/
|
|
41
|
+
readonly retries?: number;
|
|
42
|
+
/** Swap in for tests, or for a runtime with its own instrumented fetch. */
|
|
43
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
44
|
+
}
|
|
45
|
+
export declare class NacreClient {
|
|
46
|
+
#private;
|
|
47
|
+
constructor(options: ClientOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Search, bounded by what this token may see.
|
|
50
|
+
*
|
|
51
|
+
* `topK` goes through uncorrected: the filter is applied inside the index
|
|
52
|
+
* traversal, so this many permitted results come back rather than this many
|
|
53
|
+
* candidates minus whatever was stripped afterwards.
|
|
54
|
+
*/
|
|
55
|
+
search(query: string, options?: SearchOptions): Promise<readonly SearchHit[]>;
|
|
56
|
+
readonly documents: {
|
|
57
|
+
/**
|
|
58
|
+
* Queue a document. `202` and a job id, or `200` and `unchanged: true` when
|
|
59
|
+
* the same bytes are already indexed.
|
|
60
|
+
*/
|
|
61
|
+
add: (request: IngestRequest) => Promise<IngestOutcome>;
|
|
62
|
+
get: (documentId: string) => Promise<Document | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Delete a document. `true` when it was deleted, `false` when it was
|
|
65
|
+
* already gone or was never visible to this caller.
|
|
66
|
+
*
|
|
67
|
+
* It leaves search immediately — the vectors are flagged before the row is
|
|
68
|
+
* written, and collection of the points is a background job that nothing
|
|
69
|
+
* depends on.
|
|
70
|
+
*/
|
|
71
|
+
remove: (documentId: string) => Promise<boolean>;
|
|
72
|
+
};
|
|
73
|
+
readonly jobs: {
|
|
74
|
+
get: (jobId: string) => Promise<Job | undefined>;
|
|
75
|
+
/**
|
|
76
|
+
* Poll until the job leaves the queue.
|
|
77
|
+
*
|
|
78
|
+
* Ingest is asynchronous by design — parsing and embedding are slow enough
|
|
79
|
+
* that holding a request open for them is how a client times out and
|
|
80
|
+
* retries into a second copy of the same work. This is the wait, written
|
|
81
|
+
* once, so every caller does not write it slightly differently.
|
|
82
|
+
*
|
|
83
|
+
* Resolves on `indexed` **and** on `failed`: both are terminal, and a
|
|
84
|
+
* helper that threw on failure would bury the reason the job carries.
|
|
85
|
+
*/
|
|
86
|
+
wait: (jobId: string, options?: {
|
|
87
|
+
intervalMs?: number;
|
|
88
|
+
timeoutMs?: number;
|
|
89
|
+
signal?: AbortSignal;
|
|
90
|
+
}) => Promise<Job | undefined>;
|
|
91
|
+
};
|
|
92
|
+
readonly layers: {
|
|
93
|
+
/** Only the layers this token may read. The catalog is permission data. */
|
|
94
|
+
list: () => Promise<readonly Layer[]>;
|
|
95
|
+
create: (input: LayerInput) => Promise<Layer | undefined>;
|
|
96
|
+
};
|
|
97
|
+
readonly grants: {
|
|
98
|
+
list: () => Promise<readonly Grant[]>;
|
|
99
|
+
/**
|
|
100
|
+
* Issue a grant. Requires admin on the scope being granted, not admin in
|
|
101
|
+
* general — otherwise holding admin on one layer would be a way to grant
|
|
102
|
+
* yourself another.
|
|
103
|
+
*/
|
|
104
|
+
issue: (input: GrantInput) => Promise<Grant | undefined>;
|
|
105
|
+
/**
|
|
106
|
+
* Withdraw a grant. `false` when it is absent or on a scope this caller may
|
|
107
|
+
* not administer.
|
|
108
|
+
*
|
|
109
|
+
* The change is reflected in results within the propagation SLA, not
|
|
110
|
+
* instantly: the payload tags on the vectors are recomputed by the worker.
|
|
111
|
+
* `nacre_acl_propagation_lag_seconds` is what says how far behind that is.
|
|
112
|
+
*/
|
|
113
|
+
revoke: (grantId: string) => Promise<boolean>;
|
|
114
|
+
};
|
|
115
|
+
readonly serviceAccounts: {
|
|
116
|
+
list: () => Promise<readonly ServiceAccount[]>;
|
|
117
|
+
/** The response carries the key. It is not recoverable afterwards. */
|
|
118
|
+
create: (name: string) => Promise<CreatedServiceAccount>;
|
|
119
|
+
revoke: (id: string) => Promise<boolean>;
|
|
120
|
+
};
|
|
121
|
+
/** Liveness. Touches no dependency, and needs no token to be useful. */
|
|
122
|
+
health(): Promise<boolean>;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,KAAK,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,GAAG,EACH,KAAK,EACL,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACf,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;CACzC;AAoBD,qBAAa,WAAW;;gBAOV,OAAO,EAAE,aAAa;IAwGlC;;;;;;OAMG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,SAAS,EAAE,CAAC;IAyBvF,QAAQ,CAAC,SAAS;QAChB;;;WAGG;uBACkB,aAAa,KAAG,OAAO,CAAC,aAAa,CAAC;0BAuBnC,MAAM,KAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;QAkB9D;;;;;;;WAOG;6BACwB,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;MAYrD;IAID,QAAQ,CAAC,IAAI;qBACQ,MAAM,KAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC;QAgBpD;;;;;;;;;;WAUG;sBAEM,MAAM,YACJ;YAAE,UAAU,CAAC,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,KACzE,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC;MAkB5B;IAID,QAAQ,CAAC,MAAM;QACb,2EAA2E;oBAC3D,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC;wBAmBnB,UAAU,KAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;MAqB9D;IAID,QAAQ,CAAC,MAAM;oBACG,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC;QASzC;;;;WAIG;uBACkB,UAAU,KAAG,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;QAe5D;;;;;;;WAOG;0BACqB,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;MAYlD;IAID,QAAQ,CAAC,eAAe;oBACN,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC;QASlD,sEAAsE;uBACjD,MAAM,KAAG,OAAO,CAAC,qBAAqB,CAAC;qBAUzC,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;MAY7C;IAID,wEAAwE;IAClE,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;CAQjC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import { NacreError, NacreTransportError } from './errors.js';
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
const DEFAULT_RETRIES = 2;
|
|
4
|
+
const isProblem = (value) => typeof value === 'object' &&
|
|
5
|
+
value !== null &&
|
|
6
|
+
typeof value.status === 'number' &&
|
|
7
|
+
typeof value.title === 'string';
|
|
8
|
+
export class NacreClient {
|
|
9
|
+
#base;
|
|
10
|
+
#token;
|
|
11
|
+
#timeoutMs;
|
|
12
|
+
#retries;
|
|
13
|
+
#fetch;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
if (!options.baseUrl)
|
|
16
|
+
throw new TypeError('baseUrl is required');
|
|
17
|
+
if (!options.token)
|
|
18
|
+
throw new TypeError('token is required');
|
|
19
|
+
// Trailing slashes are stripped so `${base}/v1/...` cannot become `//v1`,
|
|
20
|
+
// which some proxies redirect and some reject.
|
|
21
|
+
this.#base = options.baseUrl.replace(/\/+$/, '');
|
|
22
|
+
this.#token = options.token;
|
|
23
|
+
this.#timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
24
|
+
this.#retries = Math.max(1, options.retries ?? DEFAULT_RETRIES);
|
|
25
|
+
this.#fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
26
|
+
}
|
|
27
|
+
async #once(options) {
|
|
28
|
+
const controller = new AbortController();
|
|
29
|
+
const timer = setTimeout(() => controller.abort(), this.#timeoutMs);
|
|
30
|
+
const onAbort = () => controller.abort();
|
|
31
|
+
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
32
|
+
let response;
|
|
33
|
+
try {
|
|
34
|
+
response = await this.#fetch(`${this.#base}${options.path}`, {
|
|
35
|
+
method: options.method,
|
|
36
|
+
headers: {
|
|
37
|
+
authorization: `Bearer ${this.#token}`,
|
|
38
|
+
...(options.body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
39
|
+
accept: 'application/json',
|
|
40
|
+
},
|
|
41
|
+
...(options.body === undefined ? {} : { body: JSON.stringify(options.body) }),
|
|
42
|
+
signal: controller.signal,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (cause) {
|
|
46
|
+
throw new NacreTransportError(options.signal?.aborted === true
|
|
47
|
+
? 'the request was aborted by the caller'
|
|
48
|
+
: `could not reach ${this.#base}`, undefined, { cause });
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
53
|
+
}
|
|
54
|
+
if (response.status === 204)
|
|
55
|
+
return undefined;
|
|
56
|
+
const text = await response.text();
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = text.length === 0 ? undefined : JSON.parse(text);
|
|
60
|
+
}
|
|
61
|
+
catch (cause) {
|
|
62
|
+
throw new NacreTransportError(`${options.method} ${options.path} answered ${response.status} with a body that is not JSON`, response.status, { cause });
|
|
63
|
+
}
|
|
64
|
+
if (response.ok)
|
|
65
|
+
return parsed;
|
|
66
|
+
// A problem document, or something upstream of the API answered — a proxy,
|
|
67
|
+
// a load balancer, a WAF. Saying which matters: the second is not the
|
|
68
|
+
// server refusing, and no request id exists to look up.
|
|
69
|
+
if (isProblem(parsed))
|
|
70
|
+
throw new NacreError(parsed);
|
|
71
|
+
throw new NacreTransportError(`${options.method} ${options.path} answered ${response.status} without a problem document; ` +
|
|
72
|
+
'something between this client and the API answered instead', response.status);
|
|
73
|
+
}
|
|
74
|
+
async #request(options) {
|
|
75
|
+
let attempt = 0;
|
|
76
|
+
for (;;) {
|
|
77
|
+
attempt++;
|
|
78
|
+
try {
|
|
79
|
+
return await this.#once(options);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const transient = (error instanceof NacreError && error.isTransient) ||
|
|
83
|
+
(error instanceof NacreTransportError && error.status === undefined);
|
|
84
|
+
// Retrying a delete or a grant would be a second, different write. Only
|
|
85
|
+
// the caller's own abort ends this early, and it is not transient.
|
|
86
|
+
if (!options.retryable || !transient || attempt >= this.#retries)
|
|
87
|
+
throw error;
|
|
88
|
+
if (options.signal?.aborted === true)
|
|
89
|
+
throw error;
|
|
90
|
+
await new Promise((r) => setTimeout(r, 250 * 2 ** (attempt - 1)));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/** `undefined` for 404 — absent and invisible are one answer. */
|
|
95
|
+
async #maybe(options) {
|
|
96
|
+
try {
|
|
97
|
+
return (await this.#request(options));
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error instanceof NacreError && error.isNotFound)
|
|
101
|
+
return undefined;
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ─── search ──────────────────────────────────────────────────────────────
|
|
106
|
+
/**
|
|
107
|
+
* Search, bounded by what this token may see.
|
|
108
|
+
*
|
|
109
|
+
* `topK` goes through uncorrected: the filter is applied inside the index
|
|
110
|
+
* traversal, so this many permitted results come back rather than this many
|
|
111
|
+
* candidates minus whatever was stripped afterwards.
|
|
112
|
+
*/
|
|
113
|
+
async search(query, options = {}) {
|
|
114
|
+
const body = await this.#request({
|
|
115
|
+
method: 'POST',
|
|
116
|
+
path: '/v1/search',
|
|
117
|
+
body: { query, top_k: options.topK ?? 10 },
|
|
118
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
119
|
+
retryable: true,
|
|
120
|
+
});
|
|
121
|
+
const items = body.items ?? [];
|
|
122
|
+
return items.map((h) => {
|
|
123
|
+
const hit = h;
|
|
124
|
+
return {
|
|
125
|
+
documentId: String(hit.document_id ?? ''),
|
|
126
|
+
chunkId: String(hit.chunk_id ?? ''),
|
|
127
|
+
score: Number(hit.score ?? 0),
|
|
128
|
+
text: String(hit.text ?? ''),
|
|
129
|
+
layer: String(hit.layer ?? ''),
|
|
130
|
+
title: hit.title ?? null,
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// ─── documents ───────────────────────────────────────────────────────────
|
|
135
|
+
documents = {
|
|
136
|
+
/**
|
|
137
|
+
* Queue a document. `202` and a job id, or `200` and `unchanged: true` when
|
|
138
|
+
* the same bytes are already indexed.
|
|
139
|
+
*/
|
|
140
|
+
add: async (request) => {
|
|
141
|
+
const body = (await this.#request({
|
|
142
|
+
method: 'POST',
|
|
143
|
+
path: '/v1/documents',
|
|
144
|
+
body: {
|
|
145
|
+
layer: request.layer,
|
|
146
|
+
external_id: request.externalId,
|
|
147
|
+
...(request.title === undefined ? {} : { title: request.title }),
|
|
148
|
+
...(request.content === undefined ? {} : { content: request.content }),
|
|
149
|
+
...(request.url === undefined ? {} : { url: request.url }),
|
|
150
|
+
},
|
|
151
|
+
// Idempotent on (layer, external_id) and the content hash, so a retry
|
|
152
|
+
// after a timeout cannot produce a second document or a second version.
|
|
153
|
+
retryable: true,
|
|
154
|
+
}));
|
|
155
|
+
return {
|
|
156
|
+
documentId: String(body.document_id),
|
|
157
|
+
jobId: String(body.job_id),
|
|
158
|
+
unchanged: body.status === 'indexed',
|
|
159
|
+
};
|
|
160
|
+
},
|
|
161
|
+
get: async (documentId) => {
|
|
162
|
+
const body = await this.#maybe({
|
|
163
|
+
method: 'GET',
|
|
164
|
+
path: `/v1/documents/${encodeURIComponent(documentId)}`,
|
|
165
|
+
retryable: true,
|
|
166
|
+
});
|
|
167
|
+
if (body === undefined)
|
|
168
|
+
return undefined;
|
|
169
|
+
return {
|
|
170
|
+
documentId: String(body.document_id),
|
|
171
|
+
layer: String(body.layer ?? ''),
|
|
172
|
+
title: body.title ?? null,
|
|
173
|
+
status: body.status,
|
|
174
|
+
chunkCount: Number(body.chunk_count ?? 0),
|
|
175
|
+
updatedAt: String(body.updated_at ?? ''),
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
/**
|
|
179
|
+
* Delete a document. `true` when it was deleted, `false` when it was
|
|
180
|
+
* already gone or was never visible to this caller.
|
|
181
|
+
*
|
|
182
|
+
* It leaves search immediately — the vectors are flagged before the row is
|
|
183
|
+
* written, and collection of the points is a background job that nothing
|
|
184
|
+
* depends on.
|
|
185
|
+
*/
|
|
186
|
+
remove: async (documentId) => {
|
|
187
|
+
try {
|
|
188
|
+
await this.#request({
|
|
189
|
+
method: 'DELETE',
|
|
190
|
+
path: `/v1/documents/${encodeURIComponent(documentId)}`,
|
|
191
|
+
});
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
if (error instanceof NacreError && error.isNotFound)
|
|
196
|
+
return false;
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
// ─── jobs ────────────────────────────────────────────────────────────────
|
|
202
|
+
jobs = {
|
|
203
|
+
get: async (jobId) => {
|
|
204
|
+
const body = await this.#maybe({
|
|
205
|
+
method: 'GET',
|
|
206
|
+
path: `/v1/jobs/${encodeURIComponent(jobId)}`,
|
|
207
|
+
retryable: true,
|
|
208
|
+
});
|
|
209
|
+
if (body === undefined)
|
|
210
|
+
return undefined;
|
|
211
|
+
return {
|
|
212
|
+
jobId: String(body.job_id),
|
|
213
|
+
documentId: String(body.document_id),
|
|
214
|
+
status: body.status,
|
|
215
|
+
error: body.error ?? null,
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
/**
|
|
219
|
+
* Poll until the job leaves the queue.
|
|
220
|
+
*
|
|
221
|
+
* Ingest is asynchronous by design — parsing and embedding are slow enough
|
|
222
|
+
* that holding a request open for them is how a client times out and
|
|
223
|
+
* retries into a second copy of the same work. This is the wait, written
|
|
224
|
+
* once, so every caller does not write it slightly differently.
|
|
225
|
+
*
|
|
226
|
+
* Resolves on `indexed` **and** on `failed`: both are terminal, and a
|
|
227
|
+
* helper that threw on failure would bury the reason the job carries.
|
|
228
|
+
*/
|
|
229
|
+
wait: async (jobId, options = {}) => {
|
|
230
|
+
const interval = options.intervalMs ?? 1000;
|
|
231
|
+
const deadline = Date.now() + (options.timeoutMs ?? 300_000);
|
|
232
|
+
for (;;) {
|
|
233
|
+
const job = await this.jobs.get(jobId);
|
|
234
|
+
if (job === undefined)
|
|
235
|
+
return undefined;
|
|
236
|
+
if (job.status === 'indexed' || job.status === 'failed')
|
|
237
|
+
return job;
|
|
238
|
+
if (Date.now() + interval > deadline) {
|
|
239
|
+
throw new NacreTransportError(`job ${jobId} was still ${job.status} after the timeout`);
|
|
240
|
+
}
|
|
241
|
+
if (options.signal?.aborted === true) {
|
|
242
|
+
throw new NacreTransportError('the wait was aborted by the caller');
|
|
243
|
+
}
|
|
244
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
// ─── layers ──────────────────────────────────────────────────────────────
|
|
249
|
+
layers = {
|
|
250
|
+
/** Only the layers this token may read. The catalog is permission data. */
|
|
251
|
+
list: async () => {
|
|
252
|
+
const body = (await this.#request({
|
|
253
|
+
method: 'GET',
|
|
254
|
+
path: '/v1/layers',
|
|
255
|
+
retryable: true,
|
|
256
|
+
}));
|
|
257
|
+
return (body.items ?? []).map((l) => {
|
|
258
|
+
const layer = l;
|
|
259
|
+
return {
|
|
260
|
+
id: String(layer.id),
|
|
261
|
+
slug: String(layer.slug),
|
|
262
|
+
name: String(layer.name ?? ''),
|
|
263
|
+
description: String(layer.description ?? ''),
|
|
264
|
+
documentCount: Number(layer.document_count ?? 0),
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
create: async (input) => {
|
|
269
|
+
const body = await this.#maybe({
|
|
270
|
+
method: 'POST',
|
|
271
|
+
path: '/v1/layers',
|
|
272
|
+
body: {
|
|
273
|
+
workspace_id: input.workspaceId,
|
|
274
|
+
slug: input.slug,
|
|
275
|
+
name: input.name,
|
|
276
|
+
...(input.description === undefined ? {} : { description: input.description }),
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
if (body === undefined)
|
|
280
|
+
return undefined;
|
|
281
|
+
return {
|
|
282
|
+
id: String(body.id),
|
|
283
|
+
slug: String(body.slug),
|
|
284
|
+
name: String(body.name ?? ''),
|
|
285
|
+
description: String(body.description ?? ''),
|
|
286
|
+
documentCount: Number(body.document_count ?? 0),
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
// ─── grants ──────────────────────────────────────────────────────────────
|
|
291
|
+
grants = {
|
|
292
|
+
list: async () => {
|
|
293
|
+
const body = (await this.#request({
|
|
294
|
+
method: 'GET',
|
|
295
|
+
path: '/v1/grants',
|
|
296
|
+
retryable: true,
|
|
297
|
+
}));
|
|
298
|
+
return (body.items ?? []).map((g) => grantFrom(g));
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* Issue a grant. Requires admin on the scope being granted, not admin in
|
|
302
|
+
* general — otherwise holding admin on one layer would be a way to grant
|
|
303
|
+
* yourself another.
|
|
304
|
+
*/
|
|
305
|
+
issue: async (input) => {
|
|
306
|
+
const body = await this.#maybe({
|
|
307
|
+
method: 'POST',
|
|
308
|
+
path: '/v1/grants',
|
|
309
|
+
body: {
|
|
310
|
+
principal_type: input.principalType,
|
|
311
|
+
principal_id: input.principalId,
|
|
312
|
+
scope_type: input.scopeType,
|
|
313
|
+
scope_id: input.scopeId,
|
|
314
|
+
permission: input.permission,
|
|
315
|
+
},
|
|
316
|
+
});
|
|
317
|
+
return body === undefined ? undefined : grantFrom(body);
|
|
318
|
+
},
|
|
319
|
+
/**
|
|
320
|
+
* Withdraw a grant. `false` when it is absent or on a scope this caller may
|
|
321
|
+
* not administer.
|
|
322
|
+
*
|
|
323
|
+
* The change is reflected in results within the propagation SLA, not
|
|
324
|
+
* instantly: the payload tags on the vectors are recomputed by the worker.
|
|
325
|
+
* `nacre_acl_propagation_lag_seconds` is what says how far behind that is.
|
|
326
|
+
*/
|
|
327
|
+
revoke: async (grantId) => {
|
|
328
|
+
try {
|
|
329
|
+
await this.#request({
|
|
330
|
+
method: 'DELETE',
|
|
331
|
+
path: `/v1/grants/${encodeURIComponent(grantId)}`,
|
|
332
|
+
});
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
if (error instanceof NacreError && error.isNotFound)
|
|
337
|
+
return false;
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
// ─── service accounts ────────────────────────────────────────────────────
|
|
343
|
+
serviceAccounts = {
|
|
344
|
+
list: async () => {
|
|
345
|
+
const body = (await this.#request({
|
|
346
|
+
method: 'GET',
|
|
347
|
+
path: '/v1/service-accounts',
|
|
348
|
+
retryable: true,
|
|
349
|
+
}));
|
|
350
|
+
return (body.items ?? []).map((a) => accountFrom(a));
|
|
351
|
+
},
|
|
352
|
+
/** The response carries the key. It is not recoverable afterwards. */
|
|
353
|
+
create: async (name) => {
|
|
354
|
+
const body = (await this.#request({
|
|
355
|
+
method: 'POST',
|
|
356
|
+
path: '/v1/service-accounts',
|
|
357
|
+
body: { name },
|
|
358
|
+
}));
|
|
359
|
+
return { ...accountFrom(body), key: String(body.key) };
|
|
360
|
+
},
|
|
361
|
+
revoke: async (id) => {
|
|
362
|
+
try {
|
|
363
|
+
await this.#request({
|
|
364
|
+
method: 'DELETE',
|
|
365
|
+
path: `/v1/service-accounts/${encodeURIComponent(id)}`,
|
|
366
|
+
});
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (error instanceof NacreError && error.isNotFound)
|
|
371
|
+
return false;
|
|
372
|
+
throw error;
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
// ─── health ──────────────────────────────────────────────────────────────
|
|
377
|
+
/** Liveness. Touches no dependency, and needs no token to be useful. */
|
|
378
|
+
async health() {
|
|
379
|
+
try {
|
|
380
|
+
await this.#request({ method: 'GET', path: '/v1/health', retryable: true });
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
function grantFrom(g) {
|
|
389
|
+
return {
|
|
390
|
+
id: String(g.id),
|
|
391
|
+
principalType: g.principal_type,
|
|
392
|
+
principalId: String(g.principal_id),
|
|
393
|
+
scopeType: g.scope_type,
|
|
394
|
+
scopeId: String(g.scope_id),
|
|
395
|
+
permission: g.permission,
|
|
396
|
+
effect: g.effect,
|
|
397
|
+
source: String(g.source ?? ''),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function accountFrom(a) {
|
|
401
|
+
return {
|
|
402
|
+
id: String(a.id),
|
|
403
|
+
name: String(a.name ?? ''),
|
|
404
|
+
keyPrefix: String(a.key_prefix ?? ''),
|
|
405
|
+
createdAt: String(a.created_at ?? ''),
|
|
406
|
+
lastUsedAt: a.last_used_at ?? null,
|
|
407
|
+
revokedAt: a.revoked_at ?? null,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors, shaped by the API's error contract rather than by HTTP.
|
|
3
|
+
*
|
|
4
|
+
* `docs/api.md`: every failure is `application/problem+json` (RFC 9457) with a
|
|
5
|
+
* `request_id` that matches the audit log. That correspondence is the only
|
|
6
|
+
* thing that makes an auditor's question answerable, so it is a field on the
|
|
7
|
+
* error rather than something to dig out of a body.
|
|
8
|
+
*/
|
|
9
|
+
export interface Problem {
|
|
10
|
+
readonly type: string;
|
|
11
|
+
readonly title: string;
|
|
12
|
+
readonly status: number;
|
|
13
|
+
readonly detail: string;
|
|
14
|
+
readonly instance: string;
|
|
15
|
+
readonly request_id: string;
|
|
16
|
+
}
|
|
17
|
+
export declare class NacreError extends Error {
|
|
18
|
+
readonly status: number;
|
|
19
|
+
/** The stable error identifier, e.g. `https://nacre.work/errors/not-found`. */
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly title: string;
|
|
22
|
+
readonly detail: string;
|
|
23
|
+
readonly instance: string;
|
|
24
|
+
/**
|
|
25
|
+
* Matches `request_id` in the audit log and in the server's own logs. It is
|
|
26
|
+
* the first thing to quote in a bug report and the only thing that joins a
|
|
27
|
+
* failure the caller saw to the record of what happened.
|
|
28
|
+
*/
|
|
29
|
+
readonly requestId: string;
|
|
30
|
+
constructor(problem: Problem);
|
|
31
|
+
/**
|
|
32
|
+
* Whether this is the answer the API gives for "absent, or not yours".
|
|
33
|
+
*
|
|
34
|
+
* Deliberately not two predicates. Invariant I4 says no permission and no
|
|
35
|
+
* such object are indistinguishable, down to the wording — an SDK offering
|
|
36
|
+
* `isForbidden()` alongside this would suggest a distinction the server is
|
|
37
|
+
* built never to make, and every caller who branched on it would be wrong.
|
|
38
|
+
*/
|
|
39
|
+
get isNotFound(): boolean;
|
|
40
|
+
/** Worth retrying: rate limited, or a dependency is briefly unavailable. */
|
|
41
|
+
get isTransient(): boolean;
|
|
42
|
+
}
|
|
43
|
+
/** Thrown when the server answered but not with a problem document. */
|
|
44
|
+
export declare class NacreTransportError extends Error {
|
|
45
|
+
readonly status: number | undefined;
|
|
46
|
+
constructor(message: string, status?: number, options?: {
|
|
47
|
+
cause?: unknown;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;gBAEd,OAAO,EAAE,OAAO;IAW5B;;;;;;;OAOG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,4EAA4E;IAC5E,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED,uEAAuE;AACvE,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;gBAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAK5E"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors, shaped by the API's error contract rather than by HTTP.
|
|
3
|
+
*
|
|
4
|
+
* `docs/api.md`: every failure is `application/problem+json` (RFC 9457) with a
|
|
5
|
+
* `request_id` that matches the audit log. That correspondence is the only
|
|
6
|
+
* thing that makes an auditor's question answerable, so it is a field on the
|
|
7
|
+
* error rather than something to dig out of a body.
|
|
8
|
+
*/
|
|
9
|
+
export class NacreError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
/** The stable error identifier, e.g. `https://nacre.work/errors/not-found`. */
|
|
12
|
+
type;
|
|
13
|
+
title;
|
|
14
|
+
detail;
|
|
15
|
+
instance;
|
|
16
|
+
/**
|
|
17
|
+
* Matches `request_id` in the audit log and in the server's own logs. It is
|
|
18
|
+
* the first thing to quote in a bug report and the only thing that joins a
|
|
19
|
+
* failure the caller saw to the record of what happened.
|
|
20
|
+
*/
|
|
21
|
+
requestId;
|
|
22
|
+
constructor(problem) {
|
|
23
|
+
super(`${problem.title} (${problem.status}): ${problem.detail}`);
|
|
24
|
+
this.name = 'NacreError';
|
|
25
|
+
this.status = problem.status;
|
|
26
|
+
this.type = problem.type;
|
|
27
|
+
this.title = problem.title;
|
|
28
|
+
this.detail = problem.detail;
|
|
29
|
+
this.instance = problem.instance;
|
|
30
|
+
this.requestId = problem.request_id;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether this is the answer the API gives for "absent, or not yours".
|
|
34
|
+
*
|
|
35
|
+
* Deliberately not two predicates. Invariant I4 says no permission and no
|
|
36
|
+
* such object are indistinguishable, down to the wording — an SDK offering
|
|
37
|
+
* `isForbidden()` alongside this would suggest a distinction the server is
|
|
38
|
+
* built never to make, and every caller who branched on it would be wrong.
|
|
39
|
+
*/
|
|
40
|
+
get isNotFound() {
|
|
41
|
+
return this.status === 404;
|
|
42
|
+
}
|
|
43
|
+
/** Worth retrying: rate limited, or a dependency is briefly unavailable. */
|
|
44
|
+
get isTransient() {
|
|
45
|
+
return this.status === 429 || this.status === 503 || this.status >= 500;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Thrown when the server answered but not with a problem document. */
|
|
49
|
+
export class NacreTransportError extends Error {
|
|
50
|
+
status;
|
|
51
|
+
constructor(message, status, options) {
|
|
52
|
+
super(message, options);
|
|
53
|
+
this.name = 'NacreTransportError';
|
|
54
|
+
this.status = status;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,MAAM,CAAQ;IACvB,+EAA+E;IACtE,IAAI,CAAQ;IACZ,KAAK,CAAQ;IACb,MAAM,CAAQ;IACd,QAAQ,CAAQ;IACzB;;;;OAIG;IACM,SAAS,CAAQ;IAE1B,YAAY,OAAgB;QAC1B,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,MAAM,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QAChE,IAAI,CAAC,IAAI,GAAG,YAAY,CAAA;QACxB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;QACxB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1B,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;QAChC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,UAAU,CAAA;IACrC,CAAC;IAED;;;;;;;OAOG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,CAAA;IAC5B,CAAC;IAED,4EAA4E;IAC5E,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,CAAA;IACzE,CAAC;CACF;AAED,uEAAuE;AACvE,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IACnC,MAAM,CAAoB;IAEnC,YAAY,OAAe,EAAE,MAAe,EAAE,OAA6B;QACzE,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QACvB,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nacre.work/sdk — the TypeScript client.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { NacreClient } from '@nacre.work/sdk'
|
|
6
|
+
*
|
|
7
|
+
* const nacre = new NacreClient({ baseUrl: 'https://api.nacre.work', token })
|
|
8
|
+
*
|
|
9
|
+
* const { jobId } = await nacre.documents.add({
|
|
10
|
+
* layer: 'handbook',
|
|
11
|
+
* externalId: 'onboarding-2026',
|
|
12
|
+
* content: 'The layer grows around whatever got inside.',
|
|
13
|
+
* })
|
|
14
|
+
* await nacre.jobs.wait(jobId)
|
|
15
|
+
*
|
|
16
|
+
* for (const hit of await nacre.search('onboarding')) {
|
|
17
|
+
* console.log(hit.title, hit.score)
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The token carries the organization, so no method takes one — see the note on
|
|
22
|
+
* `NacreClient`. Contract: docs/api.md, machine-readable in docs/openapi.yaml.
|
|
23
|
+
*/
|
|
24
|
+
export { NacreClient, type ClientOptions } from './client.js';
|
|
25
|
+
export { NacreError, NacreTransportError, type Problem } from './errors.js';
|
|
26
|
+
export type { CreatedServiceAccount, Document, Effect, Grant, GrantInput, IngestOutcome, IngestRequest, Job, JobStatus, Layer, LayerInput, Permission, PrincipalType, ScopeType, SearchHit, SearchOptions, ServiceAccount, } from './types.js';
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAA;AAC3E,YAAY,EACV,qBAAqB,EACrB,QAAQ,EACR,MAAM,EACN,KAAK,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,GAAG,EACH,SAAS,EACT,KAAK,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,SAAS,EACT,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nacre.work/sdk — the TypeScript client.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { NacreClient } from '@nacre.work/sdk'
|
|
6
|
+
*
|
|
7
|
+
* const nacre = new NacreClient({ baseUrl: 'https://api.nacre.work', token })
|
|
8
|
+
*
|
|
9
|
+
* const { jobId } = await nacre.documents.add({
|
|
10
|
+
* layer: 'handbook',
|
|
11
|
+
* externalId: 'onboarding-2026',
|
|
12
|
+
* content: 'The layer grows around whatever got inside.',
|
|
13
|
+
* })
|
|
14
|
+
* await nacre.jobs.wait(jobId)
|
|
15
|
+
*
|
|
16
|
+
* for (const hit of await nacre.search('onboarding')) {
|
|
17
|
+
* console.log(hit.title, hit.score)
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* The token carries the organization, so no method takes one — see the note on
|
|
22
|
+
* `NacreClient`. Contract: docs/api.md, machine-readable in docs/openapi.yaml.
|
|
23
|
+
*/
|
|
24
|
+
export { NacreClient } from './client.js';
|
|
25
|
+
export { NacreError, NacreTransportError } from './errors.js';
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,WAAW,EAAsB,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAgB,MAAM,aAAa,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire types, in the SDK's naming.
|
|
3
|
+
*
|
|
4
|
+
* The API speaks snake_case and this speaks camelCase; the mapping happens in
|
|
5
|
+
* one place, in `client.ts`, so a rename on the wire is one edit rather than a
|
|
6
|
+
* search. Nothing here carries an organization — see the note on ClientOptions.
|
|
7
|
+
*/
|
|
8
|
+
export type Permission = 'read' | 'write' | 'admin';
|
|
9
|
+
export type PrincipalType = 'user' | 'group' | 'service_account';
|
|
10
|
+
export type ScopeType = 'workspace' | 'layer' | 'document';
|
|
11
|
+
export type Effect = 'allow' | 'deny';
|
|
12
|
+
export type JobStatus = 'pending' | 'parsing' | 'indexing' | 'indexed' | 'failed';
|
|
13
|
+
export interface SearchHit {
|
|
14
|
+
readonly documentId: string;
|
|
15
|
+
readonly chunkId: string;
|
|
16
|
+
readonly score: number;
|
|
17
|
+
readonly text: string;
|
|
18
|
+
readonly layer: string;
|
|
19
|
+
readonly title: string | null;
|
|
20
|
+
}
|
|
21
|
+
export interface SearchOptions {
|
|
22
|
+
/**
|
|
23
|
+
* How many results to return. Passed through uncorrected — the filter runs
|
|
24
|
+
* inside the index traversal, so this many *permitted* results come back.
|
|
25
|
+
* There is no over-fetch to compensate for, and asking for one would be the
|
|
26
|
+
* post-filter invariant I2 is written against.
|
|
27
|
+
*/
|
|
28
|
+
readonly topK?: number;
|
|
29
|
+
readonly signal?: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
export interface IngestRequest {
|
|
32
|
+
readonly layer: string;
|
|
33
|
+
/**
|
|
34
|
+
* The caller's own identifier for the document. Ingest is idempotent on
|
|
35
|
+
* `(layer, externalId)` plus the content hash, so re-sending unchanged bytes
|
|
36
|
+
* costs nothing and does not create a version.
|
|
37
|
+
*/
|
|
38
|
+
readonly externalId: string;
|
|
39
|
+
readonly title?: string;
|
|
40
|
+
readonly content?: string;
|
|
41
|
+
readonly url?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface IngestOutcome {
|
|
44
|
+
readonly documentId: string;
|
|
45
|
+
readonly jobId: string;
|
|
46
|
+
/** `true` when the content was already indexed and nothing was queued. */
|
|
47
|
+
readonly unchanged: boolean;
|
|
48
|
+
}
|
|
49
|
+
export interface Document {
|
|
50
|
+
readonly documentId: string;
|
|
51
|
+
readonly layer: string;
|
|
52
|
+
readonly title: string | null;
|
|
53
|
+
readonly status: JobStatus;
|
|
54
|
+
readonly chunkCount: number;
|
|
55
|
+
readonly updatedAt: string;
|
|
56
|
+
}
|
|
57
|
+
export interface Job {
|
|
58
|
+
readonly jobId: string;
|
|
59
|
+
readonly documentId: string;
|
|
60
|
+
readonly status: JobStatus;
|
|
61
|
+
readonly error: string | null;
|
|
62
|
+
}
|
|
63
|
+
export interface Layer {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly slug: string;
|
|
66
|
+
readonly name: string;
|
|
67
|
+
readonly description: string;
|
|
68
|
+
readonly documentCount: number;
|
|
69
|
+
}
|
|
70
|
+
export interface LayerInput {
|
|
71
|
+
readonly workspaceId: string;
|
|
72
|
+
readonly slug: string;
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly description?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface Grant {
|
|
77
|
+
readonly id: string;
|
|
78
|
+
readonly principalType: PrincipalType;
|
|
79
|
+
readonly principalId: string;
|
|
80
|
+
readonly scopeType: ScopeType;
|
|
81
|
+
readonly scopeId: string;
|
|
82
|
+
readonly permission: Permission;
|
|
83
|
+
readonly effect: Effect;
|
|
84
|
+
readonly source: string;
|
|
85
|
+
}
|
|
86
|
+
export interface GrantInput {
|
|
87
|
+
readonly principalType: PrincipalType;
|
|
88
|
+
readonly principalId: string;
|
|
89
|
+
readonly scopeType: ScopeType;
|
|
90
|
+
readonly scopeId: string;
|
|
91
|
+
readonly permission: Permission;
|
|
92
|
+
}
|
|
93
|
+
export interface ServiceAccount {
|
|
94
|
+
readonly id: string;
|
|
95
|
+
readonly name: string;
|
|
96
|
+
readonly keyPrefix: string;
|
|
97
|
+
readonly createdAt: string;
|
|
98
|
+
readonly lastUsedAt: string | null;
|
|
99
|
+
readonly revokedAt: string | null;
|
|
100
|
+
}
|
|
101
|
+
export interface CreatedServiceAccount extends ServiceAccount {
|
|
102
|
+
/**
|
|
103
|
+
* The key, in this response and nowhere else, ever again. It is stored
|
|
104
|
+
* hashed, so it cannot be recovered from the database or from a backup.
|
|
105
|
+
*/
|
|
106
|
+
readonly key: string;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire types, in the SDK's naming.
|
|
3
|
+
*
|
|
4
|
+
* The API speaks snake_case and this speaks camelCase; the mapping happens in
|
|
5
|
+
* one place, in `client.ts`, so a rename on the wire is one edit rather than a
|
|
6
|
+
* search. Nothing here carries an organization — see the note on ClientOptions.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nacre.work/sdk",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "TypeScript SDK",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/nacre-work/nacre.git",
|
|
8
|
+
"directory": "packages/sdk"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://nacre.work",
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -b",
|
|
18
|
+
"dev": "tsx watch src/index.ts"
|
|
19
|
+
},
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"default": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist"
|
|
30
|
+
]
|
|
31
|
+
}
|