@xcitedbs/client 0.2.24 → 0.2.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +14 -4
- package/dist/client.js +27 -7
- package/dist/client.test.js +22 -0
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +33 -0
- package/llms-full.txt +13 -11
- package/llms.txt +12 -10
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AccessCheckResult, AppAuthConfig, AppEmailConfig, AppEmailTemplates, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, BranchInfo, BookmarkRecord, CheckpointRecord, CommitRecord, CompareRef, CompareResult, DatabaseContext, DiffRef, DiffResult, DocumentBatchResponse, DocumentExportFormat, ExportDocumentResult, Flags, JsonDocumentBatchItem, ImportDocumentOptions, ImportDocumentResult, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LogEntry, MergeResult, PublishResult, RebaseUserWorkspaceResult, WorkspaceInfo, MetaValue, PlatformRegisterResult, PolicySubjectInput, UnqueryResult, UnqueryTemplate, PolicyUpdateResponse, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredTriggerResponse, TriggerDefinition, StoredPolicyResponse, SubscriptionOptions, TagRecord, TextSearchQuery, TextSearchResult, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, AssetGcDryRunResult, AssetHeadResult, AssetMagicLinkListResponse, AssetMagicLinkResult, AssetShareListResponse, AssetShareRequest, AssetUnshareRequest, AssetUploadResult, CreateAssetMagicLinkRequest, ProjectAssetStorageConfig, UploadAssetOptions, PlatformDefaultDocConfResponse, VectorIndexEstimate, RagQueryOptions, RagQueryResult, RagStreamEvent, OAuthProvidersResponse, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspacesResponse, TokenPair, UserInfo, ApiKeyInfo, WriteDocumentOptions, XmlDocumentBatchItem, CreateTestSessionOptions, XCiteDBClientOptions, XCiteDBJwtClaims, TestSessionBootstrapSummary, TestSessionInfo, XCiteQuery, UserIsolationConfig, UserIsolationCreateShareParams, UserIsolationShareResult } from './types';
|
|
1
|
+
import { AccessCheckResult, AppAuthConfig, AppEmailConfig, AppEmailTemplates, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, BranchInfo, BookmarkRecord, CheckpointRecord, CommitRecord, CompareRef, CompareResult, DatabaseContext, DiffRef, DiffResult, DocumentBatchResponse, DocumentExportFormat, ExportDocumentResult, Flags, JsonDocumentBatchItem, ImportDocumentOptions, ImportDocumentResult, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LogEntry, MergeResult, PublishResult, RebaseUserWorkspaceResult, WorkspaceInfo, MetaValue, PlatformRegisterResult, PolicySubjectInput, UnqueryResult, UnqueryTemplate, PolicyUpdateResponse, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredTriggerResponse, TriggerDefinition, StoredPolicyResponse, SubscriptionOptions, TagRecord, TextSearchQuery, TextSearchResult, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, AssetGcDryRunResult, AssetHeadResult, AssetListResponse, AssetMagicLinkListResponse, AssetMagicLinkResult, AssetShareListResponse, AssetShareRequest, AssetUnshareRequest, AssetUploadResult, CreateAssetMagicLinkRequest, ListAssetsOptions, ProjectAssetStorageConfig, UploadAssetOptions, PlatformDefaultDocConfResponse, VectorIndexEstimate, RagQueryOptions, RagQueryResult, RagStreamEvent, OAuthProvidersResponse, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspacesResponse, TokenPair, UserInfo, ApiKeyInfo, WriteDocumentOptions, XmlDocumentBatchItem, CreateTestSessionOptions, XCiteDBClientOptions, XCiteDBJwtClaims, TestSessionBootstrapSummary, TestSessionInfo, XCiteQuery, UserIsolationConfig, UserIsolationCreateShareParams, UserIsolationShareResult } from './types';
|
|
2
2
|
import { WebSocketSubscription } from './websocket';
|
|
3
3
|
export declare class XCiteDBClient {
|
|
4
4
|
private baseUrl;
|
|
@@ -509,12 +509,18 @@ export declare class XCiteDBClient {
|
|
|
509
509
|
* Write an **XML** document using a JSON request body (`xml` field). The identifier is taken from `db:identifier` on the root element.
|
|
510
510
|
* For storing JSON data by key, use `writeJsonDocument`.
|
|
511
511
|
*
|
|
512
|
+
* **Pruned writes:** you may include **`db:stub="true"`** (or legacy **`<db:N…/>`**) under a parent to preserve shredded children
|
|
513
|
+
* without inlining their bodies; stubs must be empty and reference an existing row (see product `llms.txt` / OpenAPI notes).
|
|
514
|
+
* Malformed hierarchical identifiers return **400** `invalid_identifier`; invalid stub/placeholder XML returns **400** `xml_write_rejected`.
|
|
515
|
+
*
|
|
512
516
|
* On cooperative-lock conflict the server returns **423** with a {@link LockConflictBody} shape in {@link XCiteDBError.body}.
|
|
513
517
|
*/
|
|
514
518
|
writeXmlDocument(xml: string, options?: WriteDocumentOptions): Promise<void>;
|
|
515
519
|
/**
|
|
516
520
|
* Best-effort batch XML writes (`POST /api/v1/documents/batch`). Each item is independent; check `results[].ok`.
|
|
517
521
|
* Rows with `error === 'lock_conflict'` include `current_lock` (code **423** per row).
|
|
522
|
+
* **`409`** precheck rows may include **`detail`** (`identifier` for duplicates; `parent` + `inlined_child` for parent inline).
|
|
523
|
+
* Identifiers on **`db:stub="true"`** only are batch references and do not count as inlined bodies for precheck.
|
|
518
524
|
*/
|
|
519
525
|
writeXmlDocumentsBatch(items: XmlDocumentBatchItem[]): Promise<DocumentBatchResponse>;
|
|
520
526
|
/**
|
|
@@ -534,13 +540,15 @@ export declare class XCiteDBClient {
|
|
|
534
540
|
writeDocumentJson(xml: string, options?: WriteDocumentOptions): Promise<void>;
|
|
535
541
|
queryByIdentifier(identifier: string, flags?: Flags, filter?: string, pathFilter?: string): Promise<string[]>;
|
|
536
542
|
/**
|
|
537
|
-
* Shallow read
|
|
538
|
-
*
|
|
539
|
-
*
|
|
543
|
+
* Shallow read (`flags=NoChildren,KeepIndexNodes,FirstMatch` on `GET /api/v1/documents/by-id`):
|
|
544
|
+
* root element with inline leaves plus **identifier-bearing stub elements** (`db:stub="true"`) for shredded
|
|
545
|
+
* child slots instead of opaque `db:N*` placeholders. Safe to round-trip with {@link writeXmlDocument}.
|
|
546
|
+
* For sidebar / AST navigation, pair with {@link listIdentifierChildren} (e.g. `Promise.all` of shallow + children).
|
|
540
547
|
*/
|
|
541
548
|
queryByIdentifierShallow(identifier: string, filter?: string, pathFilter?: string): Promise<string[]>;
|
|
542
549
|
/**
|
|
543
550
|
* Load a document with all shredded children inlined (`FirstMatch,IncludeChildren` on `GET /by-id`).
|
|
551
|
+
* The returned array has **length 0 or 1**; when present, index `0` is the full XML string.
|
|
544
552
|
* Use this for editor round-trips. For navigation without loading the full subtree, use
|
|
545
553
|
* {@link queryByIdentifierShallow} plus {@link listIdentifierChildren}.
|
|
546
554
|
*/
|
|
@@ -678,6 +686,8 @@ export declare class XCiteDBClient {
|
|
|
678
686
|
headAsset(uriOrIdentifier: string, opts?: {
|
|
679
687
|
ml?: string;
|
|
680
688
|
}): Promise<AssetHeadResult>;
|
|
689
|
+
/** `GET /api/v1/assets` — paginated, ABAC-filtered listing. Magic-link auth is rejected by the server. */
|
|
690
|
+
listAssets(opts?: ListAssetsOptions): Promise<AssetListResponse>;
|
|
681
691
|
/** Admin: GC dry-run — manifest vs live meta references (`POST /api/v1/admin/assets/gc/dry-run`). */
|
|
682
692
|
adminAssetsGcDryRun(opts?: {
|
|
683
693
|
ownerUserId?: string;
|
package/dist/client.js
CHANGED
|
@@ -1538,6 +1538,10 @@ class XCiteDBClient {
|
|
|
1538
1538
|
* Write an **XML** document using a JSON request body (`xml` field). The identifier is taken from `db:identifier` on the root element.
|
|
1539
1539
|
* For storing JSON data by key, use `writeJsonDocument`.
|
|
1540
1540
|
*
|
|
1541
|
+
* **Pruned writes:** you may include **`db:stub="true"`** (or legacy **`<db:N…/>`**) under a parent to preserve shredded children
|
|
1542
|
+
* without inlining their bodies; stubs must be empty and reference an existing row (see product `llms.txt` / OpenAPI notes).
|
|
1543
|
+
* Malformed hierarchical identifiers return **400** `invalid_identifier`; invalid stub/placeholder XML returns **400** `xml_write_rejected`.
|
|
1544
|
+
*
|
|
1541
1545
|
* On cooperative-lock conflict the server returns **423** with a {@link LockConflictBody} shape in {@link XCiteDBError.body}.
|
|
1542
1546
|
*/
|
|
1543
1547
|
async writeXmlDocument(xml, options) {
|
|
@@ -1550,6 +1554,8 @@ class XCiteDBClient {
|
|
|
1550
1554
|
/**
|
|
1551
1555
|
* Best-effort batch XML writes (`POST /api/v1/documents/batch`). Each item is independent; check `results[].ok`.
|
|
1552
1556
|
* Rows with `error === 'lock_conflict'` include `current_lock` (code **423** per row).
|
|
1557
|
+
* **`409`** precheck rows may include **`detail`** (`identifier` for duplicates; `parent` + `inlined_child` for parent inline).
|
|
1558
|
+
* Identifiers on **`db:stub="true"`** only are batch references and do not count as inlined bodies for precheck.
|
|
1553
1559
|
*/
|
|
1554
1560
|
async writeXmlDocumentsBatch(items) {
|
|
1555
1561
|
const body = {
|
|
@@ -1630,19 +1636,20 @@ class XCiteDBClient {
|
|
|
1630
1636
|
filter,
|
|
1631
1637
|
path_filter: pathFilter,
|
|
1632
1638
|
});
|
|
1633
|
-
|
|
1634
|
-
return Array.isArray(rows) ? rows.map((x) => this.isoUnprefixId(String(x))) : rows;
|
|
1639
|
+
return this.request('GET', `/api/v1/documents/by-id${q}`);
|
|
1635
1640
|
}
|
|
1636
1641
|
/**
|
|
1637
|
-
* Shallow read
|
|
1638
|
-
*
|
|
1639
|
-
*
|
|
1642
|
+
* Shallow read (`flags=NoChildren,KeepIndexNodes,FirstMatch` on `GET /api/v1/documents/by-id`):
|
|
1643
|
+
* root element with inline leaves plus **identifier-bearing stub elements** (`db:stub="true"`) for shredded
|
|
1644
|
+
* child slots instead of opaque `db:N*` placeholders. Safe to round-trip with {@link writeXmlDocument}.
|
|
1645
|
+
* For sidebar / AST navigation, pair with {@link listIdentifierChildren} (e.g. `Promise.all` of shallow + children).
|
|
1640
1646
|
*/
|
|
1641
1647
|
async queryByIdentifierShallow(identifier, filter, pathFilter) {
|
|
1642
1648
|
return this.queryByIdentifier(identifier, 'NoChildren,KeepIndexNodes,FirstMatch', filter, pathFilter);
|
|
1643
1649
|
}
|
|
1644
1650
|
/**
|
|
1645
1651
|
* Load a document with all shredded children inlined (`FirstMatch,IncludeChildren` on `GET /by-id`).
|
|
1652
|
+
* The returned array has **length 0 or 1**; when present, index `0` is the full XML string.
|
|
1646
1653
|
* Use this for editor round-trips. For navigation without loading the full subtree, use
|
|
1647
1654
|
* {@link queryByIdentifierShallow} plus {@link listIdentifierChildren}.
|
|
1648
1655
|
*/
|
|
@@ -1674,8 +1681,7 @@ class XCiteDBClient {
|
|
|
1674
1681
|
if (pq.filter_any_meta === true) {
|
|
1675
1682
|
params.any_meta = '1';
|
|
1676
1683
|
}
|
|
1677
|
-
|
|
1678
|
-
return Array.isArray(rows) ? rows.map((x) => this.isoUnprefixId(String(x))) : rows;
|
|
1684
|
+
return this.request('GET', `/api/v1/documents${buildQuery(params)}`);
|
|
1679
1685
|
}
|
|
1680
1686
|
async deleteDocument(identifier) {
|
|
1681
1687
|
await this.request('DELETE', `/api/v1/documents/by-id${buildQuery({ identifier: this.isoPrefixId(identifier) })}`);
|
|
@@ -2257,6 +2263,20 @@ class XCiteDBClient {
|
|
|
2257
2263
|
this.notifySessionInvalidIfNeeded(path, 401);
|
|
2258
2264
|
throw new types_1.XCiteDBError('Request failed after retry', 401, null);
|
|
2259
2265
|
}
|
|
2266
|
+
/** `GET /api/v1/assets` — paginated, ABAC-filtered listing. Magic-link auth is rejected by the server. */
|
|
2267
|
+
async listAssets(opts) {
|
|
2268
|
+
const params = {};
|
|
2269
|
+
if (opts?.prefix)
|
|
2270
|
+
params.prefix = opts.prefix;
|
|
2271
|
+
if (typeof opts?.limit === 'number')
|
|
2272
|
+
params.limit = String(opts.limit);
|
|
2273
|
+
if (opts?.cursor)
|
|
2274
|
+
params.cursor = opts.cursor;
|
|
2275
|
+
if (opts?.includeHeader)
|
|
2276
|
+
params.include_header = 'true';
|
|
2277
|
+
const q = buildQuery(params);
|
|
2278
|
+
return this.request('GET', `/api/v1/assets${q}`, undefined);
|
|
2279
|
+
}
|
|
2260
2280
|
/** Admin: GC dry-run — manifest vs live meta references (`POST /api/v1/admin/assets/gc/dry-run`). */
|
|
2261
2281
|
async adminAssetsGcDryRun(opts) {
|
|
2262
2282
|
const q = opts?.ownerUserId && opts.ownerUserId.trim()
|
package/dist/client.test.js
CHANGED
|
@@ -32,6 +32,28 @@ const types_js_1 = require("./types.js");
|
|
|
32
32
|
globalThis.fetch = orig;
|
|
33
33
|
}
|
|
34
34
|
});
|
|
35
|
+
(0, node_test_1.it)('queryByIdentifier / queryDocuments return XML bodies unmodified under userIsolation', async () => {
|
|
36
|
+
const xml = '<?xml version="1.0"?><doc xmlns:db="http://www.xcitedb.com/schema"><a href="https://example.com//path">x</a></doc>';
|
|
37
|
+
const orig = globalThis.fetch;
|
|
38
|
+
globalThis.fetch = node_test_1.mock.fn(async () => {
|
|
39
|
+
return new Response(JSON.stringify([xml]), { status: 200 });
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
const c = new client_js_1.XCiteDBClient({
|
|
43
|
+
baseUrl: 'http://127.0.0.1:9',
|
|
44
|
+
apiKey: 'test-key',
|
|
45
|
+
userIsolation: { enabled: true, namespace: '/users/{userId}' },
|
|
46
|
+
});
|
|
47
|
+
c.setAppUserTokens('header.eyJzdWIiOiJ1c2VyLTEifQ.sig');
|
|
48
|
+
const a = await c.queryByIdentifier('/x');
|
|
49
|
+
strict_1.default.deepEqual(a, [xml]);
|
|
50
|
+
const b = await c.queryDocuments({ match: '/x' });
|
|
51
|
+
strict_1.default.deepEqual(b, [xml]);
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
globalThis.fetch = orig;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
35
57
|
(0, node_test_1.it)('403 becomes XCiteDBForbiddenError with policy_id and request ids', async () => {
|
|
36
58
|
const orig = globalThis.fetch;
|
|
37
59
|
globalThis.fetch = node_test_1.mock.fn(async () => {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { XCiteDBClient } from './client';
|
|
2
2
|
export { parseAssetUri, formatAssetUri, collectIdentifiersFromText, ASSET_URI_PREFIX } from './assetUri';
|
|
3
3
|
export { WebSocketSubscription } from './websocket';
|
|
4
|
-
export type { AccessCheckResult, ApiKeyInfo, AppAuthConfig, AppEmailConfig, AppEmailSmtpConfig, AppEmailTemplateEntry, AppEmailTemplates, AppEmailWebhookConfig, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, BookmarkRecord, BranchInfo, BranchListItem, CheckpointRecord, CommitRecord, CompareEntry, CompareRef, CompareResult, DatabaseContext, DiffEntry, DiffRef, DiffResult, DocumentBatchResponse, DocumentBatchResultRow, DocumentExportFormat, DocumentImportFormat, ExportDocumentResult, Flags, ImportDocumentOptions, ImportDocumentResult, JsonDocumentData, JsonDocumentBatchItem, IdentifierChildNode, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LockConflictBody, LockExpiredBody, LockUnknownBody, MergeConflict, MergeResult, OAuthProviderInfo, OAuthProvidersResponse, OwnedTenantInfo, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspaceOrg, PlatformWorkspacesResponse, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, AssetGcDryRunResult, AssetHeadResult, AssetMagicLinkListResponse, AssetMagicLinkRecord, AssetMagicLinkResult, AssetShareListEntry, AssetShareListResponse, AssetShareRequest, AssetStorageImport, AssetStorageMount, AssetStorageTarget, AssetStorageTargetType, AssetUnshareRequest, AssetUploadResult, CreateAssetMagicLinkRequest, ProjectAssetStorageConfig, UploadAssetOptions, PlatformDefaultDocConfResponse, LogEntry, MetaValue, PlatformRegisterResult, PolicyUpdateResponse, PublishConflict, PublishResult, RebaseUserWorkspaceResult, PolicyConditions, PolicyIdentifierPattern, PolicyResources, PolicySubjectInput, PolicySubjects, RagQueryOptions, RagQueryResult, RagStreamEvent, RealtimeEvent, SearchIndexingProgress, SecurityConfig, SecurityPolicy, StoredPolicyResponse, StoredTriggerResponse, SubscriptionOptions, TagRecord, TextSearchHit, TextSearchQuery, TextSearchResult, TriggerDefinition, TokenPair, UserInfo, UserIsolationConfig, UserIsolationCreateShareParams, UserIsolationOptions, UserIsolationShareMode, UserIsolationShareResult, WorkspaceInfo, WriteDocumentOptions, XmlDocumentBatchItem, CreateTestSessionOptions, TestSessionBootstrap, TestSessionBootstrapSummary, TestSessionInfo, XCiteDBClientOptions, XCiteDBErrorExtras, XCiteDBJwtClaims, UnqueryResult, UnqueryTemplate, XCiteQuery, } from './types';
|
|
4
|
+
export type { AccessCheckResult, ApiKeyInfo, AppAuthConfig, AppEmailConfig, AppEmailSmtpConfig, AppEmailTemplateEntry, AppEmailTemplates, AppEmailWebhookConfig, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, BookmarkRecord, BranchInfo, BranchListItem, CheckpointRecord, CommitRecord, CompareEntry, CompareRef, CompareResult, DatabaseContext, DiffEntry, DiffRef, DiffResult, DocumentBatchResponse, DocumentBatchResultRow, DocumentExportFormat, DocumentImportFormat, ExportDocumentResult, Flags, ImportDocumentOptions, ImportDocumentResult, JsonDocumentData, JsonDocumentBatchItem, IdentifierChildNode, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LockConflictBody, LockExpiredBody, LockUnknownBody, MergeConflict, MergeResult, OAuthProviderInfo, OAuthProvidersResponse, OwnedTenantInfo, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspaceOrg, PlatformWorkspacesResponse, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, AssetGcDryRunResult, AssetHeadResult, AssetListItem, AssetListResponse, AssetMagicLinkListResponse, AssetMagicLinkRecord, AssetMagicLinkResult, AssetShareListEntry, AssetShareListResponse, AssetShareRequest, AssetStorageImport, AssetStorageMount, AssetStorageTarget, AssetStorageTargetType, AssetUnshareRequest, AssetUploadResult, CreateAssetMagicLinkRequest, ListAssetsOptions, ProjectAssetStorageConfig, UploadAssetOptions, PlatformDefaultDocConfResponse, LogEntry, MetaValue, PlatformRegisterResult, PolicyUpdateResponse, PublishConflict, PublishResult, RebaseUserWorkspaceResult, PolicyConditions, PolicyIdentifierPattern, PolicyResources, PolicySubjectInput, PolicySubjects, RagQueryOptions, RagQueryResult, RagStreamEvent, RealtimeEvent, SearchIndexingProgress, SecurityConfig, SecurityPolicy, StoredPolicyResponse, StoredTriggerResponse, SubscriptionOptions, TagRecord, TextSearchHit, TextSearchQuery, TextSearchResult, TriggerDefinition, TokenPair, UserInfo, UserIsolationConfig, UserIsolationCreateShareParams, UserIsolationOptions, UserIsolationShareMode, UserIsolationShareResult, WorkspaceInfo, WriteDocumentOptions, XmlDocumentBatchItem, CreateTestSessionOptions, TestSessionBootstrap, TestSessionBootstrapSummary, TestSessionInfo, XCiteDBClientOptions, XCiteDBErrorExtras, XCiteDBJwtClaims, UnqueryResult, UnqueryTemplate, XCiteQuery, } from './types';
|
|
5
5
|
export { XCiteDBError, XCiteDBForbiddenError, XCiteDBNotFoundError, XCiteDBAuthError, XCiteDBLockConflictError, } from './types';
|
package/dist/types.d.ts
CHANGED
|
@@ -194,6 +194,34 @@ export interface AssetHeadResult {
|
|
|
194
194
|
size: number;
|
|
195
195
|
etag?: string;
|
|
196
196
|
}
|
|
197
|
+
/** One row of `GET /api/v1/assets`. Header fields are present only when `include_header=true`. */
|
|
198
|
+
export interface AssetListItem {
|
|
199
|
+
identifier: string;
|
|
200
|
+
uri: string;
|
|
201
|
+
content_type?: string;
|
|
202
|
+
size?: number;
|
|
203
|
+
sha256?: string;
|
|
204
|
+
etag?: string;
|
|
205
|
+
target_name?: string;
|
|
206
|
+
owner_user_id?: string;
|
|
207
|
+
created?: string;
|
|
208
|
+
}
|
|
209
|
+
/** `GET /api/v1/assets` paginated, ABAC-filtered. */
|
|
210
|
+
export interface AssetListResponse {
|
|
211
|
+
items: AssetListItem[];
|
|
212
|
+
next_cursor: string | null;
|
|
213
|
+
}
|
|
214
|
+
/** Options for {@link XCiteDBClient.listAssets}. */
|
|
215
|
+
export interface ListAssetsOptions {
|
|
216
|
+
/** Filter by canonical id prefix (e.g. `/users/abc/assets/`). */
|
|
217
|
+
prefix?: string;
|
|
218
|
+
/** Page size, 1..1000 (default 200). */
|
|
219
|
+
limit?: number;
|
|
220
|
+
/** Last identifier from previous page (exclusive). */
|
|
221
|
+
cursor?: string;
|
|
222
|
+
/** Include per-asset header fields (`content_type`, `size`, …). */
|
|
223
|
+
includeHeader?: boolean;
|
|
224
|
+
}
|
|
197
225
|
/** `POST /api/v1/admin/assets/gc/dry-run` (admin). */
|
|
198
226
|
export interface AssetGcDryRunResult {
|
|
199
227
|
manifest_count: number;
|
|
@@ -555,6 +583,11 @@ export interface DocumentBatchResultRow {
|
|
|
555
583
|
*/
|
|
556
584
|
error?: string;
|
|
557
585
|
code?: number;
|
|
586
|
+
/**
|
|
587
|
+
* Structured context for XML batch **`409`** precheck rows, e.g. `{ identifier }` for
|
|
588
|
+
* `duplicate_identifier_in_batch` or `{ parent, inlined_child }` for `parent_inlines_batch_member`.
|
|
589
|
+
*/
|
|
590
|
+
detail?: Record<string, string>;
|
|
558
591
|
/** Present when `error === 'lock_conflict'` (HTTP-style code 423 in batch row). */
|
|
559
592
|
current_lock?: LockInfo;
|
|
560
593
|
}
|
package/llms-full.txt
CHANGED
|
@@ -65,7 +65,7 @@ Legacy REST paths under `/api/v1/branches`, `/commits`, `/tags`, `/diff` remain
|
|
|
65
65
|
|
|
66
66
|
7. **Do not mock XciteDB in tests — use ephemeral test sessions instead.** Unlike most BaaS platforms, XciteDB has built-in support for isolated, throwaway database sessions specifically designed for wet integration tests. Mocking the client skips the actual storage, versioning, querying, and ABAC behavior, producing tests that don't catch real integration issues. Use `createTestSession()` / `test_session()` / `create_test_session()` (SDK helpers) or `POST /api/v1/test/sessions` directly to get a real LMDB under `_test/<uuid>/` (empty by default, or **overlay** on read-only production with **`{"overlay":true}`** / **`overlay: true`** / **`test_session_overlay`**). See "Ephemeral test sessions" below.
|
|
67
67
|
|
|
68
|
-
8. **Identifier strings (minting).** The
|
|
68
|
+
8. **Identifier strings (minting).** The API canonicalizes hierarchical paths (**leading `/`**, **no trailing `/`**). **`POST /api/v1/documents`** rejects malformed ids with **`400`** JSON **`{ "error": "invalid_identifier", "reason", "identifier", "detail" }`**: no commas, no ASCII control characters (including **`0x01`**), no `//` or empty segments, no adjacent duplicate segments (e.g. `/a/b/b/c`). Reserved namespaces include **`/_xcitedb/`**, **`/assets/`**, **`/public/assets/`**, and **`/public/shared/<tenant>/assets/`**. **`identifier_hierarchy_max_depth`** (default **4**) tunes hierarchy indexing; deeper paths still work but **`GET …/identifier-children`** may scan.
|
|
69
69
|
|
|
70
70
|
---
|
|
71
71
|
|
|
@@ -430,7 +430,7 @@ With `Content-Type: application/json`:
|
|
|
430
430
|
|
|
431
431
|
With `Content-Type: application/xml`: send raw XML body.
|
|
432
432
|
|
|
433
|
-
The identifier is extracted from the `db:identifier` attribute in the root XML element.
|
|
433
|
+
The identifier is extracted from the `db:identifier` attribute in the root XML element. Malformed root identifiers return **`400`** (`invalid_identifier`). Invalid stub/placeholder XML on write returns **`400`** with `error: "xml_write_rejected"` and a `message` string.
|
|
434
434
|
|
|
435
435
|
## Get document by identifier
|
|
436
436
|
|
|
@@ -440,7 +440,8 @@ Query parameters: `identifier` (required), `flags` (optional: `FirstMatch`, `Inc
|
|
|
440
440
|
|
|
441
441
|
### Shallow node + subtree navigation
|
|
442
442
|
|
|
443
|
-
- **`flags=NoChildren,KeepIndexNodes,FirstMatch`**: returns the matching node with inline leaf content plus
|
|
443
|
+
- **`flags=NoChildren,KeepIndexNodes,FirstMatch`**: returns the matching node with inline leaf content plus **identifier-bearing stub elements** **`db:stub="true"`** for shredded child slots (real element names; avoids loading the full deep subtree in one response). The engine still stores internal **`<db:N…/>`** placeholders on disk.
|
|
444
|
+
- **`GET …/by-id`** with **`FirstMatch,IncludeChildren`** returns a JSON array of **length 0 or 1**; index `0` is the full assembled XML when present.
|
|
444
445
|
- Combine with **`GET /api/v1/documents/identifier-children?parent_path=…`** for the next level of hierarchy (`segment`, `full_path`, `is_identifier`, `has_children`).
|
|
445
446
|
- **JavaScript SDK:** `queryByIdentifierFull(id)` loads **`FirstMatch,IncludeChildren`** for editor round-trips; **`queryByIdentifierShallow(id)`** + **`listChildIdentifiers(id)`** (e.g. `Promise.all` client-side) for sidebar / tree expansion.
|
|
446
447
|
|
|
@@ -450,16 +451,17 @@ You may `POST /api/v1/documents` with a root element whose `db:identifier` is a
|
|
|
450
451
|
|
|
451
452
|
### XML shredding semantics (must read)
|
|
452
453
|
|
|
453
|
-
- **Auto-shred.** Any element with **`db:identifier`** is stored as its own LMDB row. The parent’s stored XML keeps
|
|
454
|
+
- **Auto-shred.** Any element with **`db:identifier`** is stored as its own LMDB row. The parent’s stored XML keeps an internal **`<db:N…/>`** placeholder for that slot (engine-only). There is **no** size threshold and **no** opt-out.
|
|
455
|
+
- **Pruned writes.** Clients may send **stub** elements (**`db:stub="true"`**) or legacy **`<db:N…/>`** under a parent to preserve subtrees without inlining full XML. Stubs must be empty, reference an **existing** identifier, and must not appear at the document root; violations are **`400`** (`xml_write_rejected`).
|
|
454
456
|
- **`is_top` is a marker only.** It registers a **`TOP:<xcitepath>`** alias for tooling; it does **not** change shredding, merge, or overwrite behavior.
|
|
455
|
-
- **Batch ordering.** **`POST /api/v1/documents/batch`** processes **`items[]`** **sequentially**. Each item’s XML is shredded so **every** `db:identifier` in that payload becomes (or overwrites) its own row. Precheck returns per-row **`409`**: **`duplicate_identifier_in_batch`** when the same canonical root id appears in more than one item (the **later** row is rejected), and **`parent_inlines_batch_member`** when one item’s XML still
|
|
456
|
-
- **
|
|
457
|
+
- **Batch ordering.** **`POST /api/v1/documents/batch`** processes **`items[]`** **sequentially**. Each item’s XML is shredded so **every** `db:identifier` in that payload becomes (or overwrites) its own row **except** ids that appear **only** on **`db:stub="true"`** elements (references, not inlined bodies). Precheck returns per-row **`409`**: **`duplicate_identifier_in_batch`** when the same canonical root id appears in more than one item (the **later** row is rejected), and **`parent_inlines_batch_member`** when one item’s XML still **fully inlines** another item’s **root** id in the same batch (stubs referencing another batch member are allowed).
|
|
458
|
+
- **Idempotency (retries).** Re-sending the same XML with the same **`X-Date`** (or unversioned mode) is a no-op when the revision is unchanged; reuse the date key on retries.
|
|
457
459
|
|
|
458
460
|
**Round-trip:** Element structure, child order, and text are preserved. The server may add **`db:order`**, **`db:xcitepath`**, **`xmlns:db`**. Attribute order and insignificant whitespace are **not** byte-stable—compare by DOM, not raw bytes.
|
|
459
461
|
|
|
460
462
|
### Batch XML writes
|
|
461
463
|
|
|
462
|
-
**`POST /api/v1/documents/batch`** — JSON body **`{ "items": [ { "xml": "<…>", "is_top": true, "compare_attributes": false, "identifier": "/optional/match" }, … ] }`**. Response **`200`** with **`{ "results": [ { "index", "ok", "identifier", "error"?, "code"?, "current_lock"? } ] }`** (
|
|
464
|
+
**`POST /api/v1/documents/batch`** — JSON body **`{ "items": [ { "xml": "<…>", "is_top": true, "compare_attributes": false, "identifier": "/optional/match" }, … ] }`**. Response **`200`** with **`{ "results": [ { "index", "ok", "identifier", "error"?, "code"?, "detail"?, "current_lock"? } ] }`** (`detail` for **`409`** precheck rows: duplicate → `{ "identifier": "<root>" }`; parent inline → `{ "parent": "<root>", "inlined_child": "<other>" }`). Best-effort: later rows still run when earlier rows fail. JavaScript: **`writeXmlDocumentsBatch`**. Python: **`write_xml_documents_batch`**. C++: **`write_xml_documents_batch`**.
|
|
463
465
|
|
|
464
466
|
### Minimal SPA editor recipe
|
|
465
467
|
|
|
@@ -487,7 +489,7 @@ async function saveDirty(items: XmlDocumentBatchItem[]) {
|
|
|
487
489
|
}
|
|
488
490
|
```
|
|
489
491
|
|
|
490
|
-
**
|
|
492
|
+
**Batch save rules:** (1) At most **one** batch item per flush may use a given root **`db:identifier`** (`duplicate_identifier_in_batch`). (2) Do not ship a parent that **fully inlines** another item’s root id in the same batch (`parent_inlines_batch_member`); **`db:stub="true"`** references to another batch member are **allowed**. (3) **`is_top`** does not relax (1) or (2).
|
|
491
493
|
|
|
492
494
|
## Delete document
|
|
493
495
|
|
|
@@ -1583,10 +1585,10 @@ interface DatabaseContext {
|
|
|
1583
1585
|
- `importDocument(file, options?)` → `ImportDocumentResult` — multipart `POST /api/v1/documents/import`
|
|
1584
1586
|
- `exportDocument(identifier, format?, options?)` → `ExportDocumentResult` — binary `GET /api/v1/documents/export`
|
|
1585
1587
|
- `queryByIdentifier(identifier, flags?, filter?, pathFilter?)` → `string[]`
|
|
1586
|
-
- `queryByIdentifierFull(identifier, filter?, pathFilter?)` → `string[]` — `FirstMatch,IncludeChildren` (editor load)
|
|
1587
|
-
- `queryByIdentifierShallow(identifier, filter?, pathFilter?)` → `string[]` — `NoChildren,KeepIndexNodes,FirstMatch`
|
|
1588
|
+
- `queryByIdentifierFull(identifier, filter?, pathFilter?)` → `string[]` — `FirstMatch,IncludeChildren` (editor load); array length **0 or 1**
|
|
1589
|
+
- `queryByIdentifierShallow(identifier, filter?, pathFilter?)` → `string[]` — `NoChildren,KeepIndexNodes,FirstMatch` (skeleton with **`db:stub="true"`** child markers)
|
|
1588
1590
|
- `listChildIdentifiers(parentPath?)` → `ListIdentifierChildrenResult` — alias of `listIdentifierChildren`
|
|
1589
|
-
- `writeXmlDocumentsBatch(items)` → `DocumentBatchResponse` — `POST /api/v1/documents/batch` (per-row `409
|
|
1591
|
+
- `writeXmlDocumentsBatch(items)` → `DocumentBatchResponse` — `POST /api/v1/documents/batch` (per-row `409` + optional **`detail`**; stubs exempt from duplicate-root / parent-inline checks per semantics above)
|
|
1590
1592
|
- `queryDocuments(query: XCiteQuery, flags?, filter?, pathFilter?)` → `string[]`
|
|
1591
1593
|
- `deleteDocument(identifier)` → `void`
|
|
1592
1594
|
- `listIdentifiers(query: XCiteQuery)` → `ListIdentifiersResult`
|
package/llms.txt
CHANGED
|
@@ -74,7 +74,7 @@ Legacy REST paths (`/api/v1/branches`, `/commits`, `/tags`, `/diff`) remain as *
|
|
|
74
74
|
|
|
75
75
|
12. **`X-Date` / `context.date` is not “server clock only.”** Revisions are keyed by the **instant you send**, not an implicit “now” when you set the header. To record a document under a **business date** (published, approved, effective), set **`X-Date`** or **`context.date`** to that instant before writing. Omitting **`X-Date`** does **not** substitute the current time on the write path — it selects **flat** writes (see convention 4).
|
|
76
76
|
|
|
77
|
-
13. **Identifier strings (minting).** The
|
|
77
|
+
13. **Identifier strings (minting).** The API canonicalizes paths (**leading `/`**, **no trailing `/`**). **`POST /api/v1/documents`** rejects malformed hierarchical ids with **`400`** and JSON **`{ "error": "invalid_identifier", "reason", "identifier", "detail" }`**: no commas, no ASCII control characters (including **`0x01`** LMDB separator), no `//` or empty path segments, no **adjacent duplicate** path segments (e.g. `/a/b/b/c`). Reserved namespaces include **`/_xcitedb/`**, **`/assets/`**, **`/public/assets/`**, and **`/public/shared/<tenant>/assets/`**. Server config **`identifier_hierarchy_max_depth`** defaults to **4**—deeper paths still work, but **`identifier-children`** listing may fall back to a scan.
|
|
78
78
|
|
|
79
79
|
## API key capability matrix (typical)
|
|
80
80
|
|
|
@@ -168,12 +168,14 @@ When you build a backend that calls XCiteDB on behalf of users:
|
|
|
168
168
|
|
|
169
169
|
## XML shredding semantics (must read)
|
|
170
170
|
|
|
171
|
-
- **Auto-shred.** Any element with **`db:identifier`** is stored as its own LMDB row. The parent’s stored XML keeps
|
|
171
|
+
- **Auto-shred.** Any element with **`db:identifier`** is stored as its own LMDB row. The parent’s stored XML keeps an internal **`<db:N…/>`** placeholder for that slot (engine-only). There is **no** size threshold and **no** opt-out.
|
|
172
|
+
- **Shallow reads (`NoChildren,KeepIndexNodes`).** The API returns **identifier-bearing stubs** instead of opaque placeholders: **`<elem db:identifier="…" db:xcitepath="…" db:order="…" db:stub="true"/>`** (real element name, empty element). Clients may round-trip these stubs through **`writeXmlDocument`**; preserved subtrees are not deleted. You may also send legacy **`<db:N…/>`** placeholders from older clients; the engine resolves them under the parent’s **`db:xcitepath`**.
|
|
173
|
+
- **Pruned writes.** You may mix **full** identified subtrees and **stub** markers (or placeholders) under one parent. Stubs must be **empty** (no element children, no non-whitespace text), carry **`db:identifier`** (or legacy **`identifier`**) pointing at an **existing** row, and optional **`db:order`**, **`db:xcitepath`**, **`xmlns:db`** only. The document root must not be a stub. Violations yield **`400`** with `error: "xml_write_rejected"` and a **`message`** string (`stub_*` / `placeholder_*`).
|
|
172
174
|
- **`is_top` is a marker only.** It registers a **`TOP:<xcitepath>`** alias for tooling; it does **not** change shredding, merge, or overwrite behavior. Leaving **`true`** on every write is normal.
|
|
173
|
-
- **`POST /api/v1/documents/batch`** runs items **in order**; each item’s write replaces LMDB rows for **every** `db:identifier` present in that item’s XML. The server prechecks each row and may return **`409`** with **`duplicate_identifier_in_batch`** (same root id in two items) or **`parent_inlines_batch_member`** (a parent’s XML still
|
|
174
|
-
- **
|
|
175
|
+
- **`POST /api/v1/documents/batch`** runs items **in order**; each item’s write replaces LMDB rows for **every** `db:identifier` present in that item’s XML **except** identifiers that appear only on **`db:stub="true"`** elements (those are references, not inlined document bodies). The server prechecks each row and may return **`409`** with **`duplicate_identifier_in_batch`** (same root id in two items) or **`parent_inlines_batch_member`** (a parent’s XML still **fully inlines** another item’s root id). Failed rows include a JSON **`detail`** object: for duplicates **`{ "identifier": "<root>" }`**; for parent inline **`{ "parent": "<root>", "inlined_child": "<other root>" }`**. Check **`results[i].ok`** on the JSON response.
|
|
176
|
+
- **Idempotency (retries).** Re-sending the same XML body with the same **`X-Date`** (or unversioned mode) is a safe no-op when the stored revision is unchanged; use the same date key on client retries to avoid duplicate logical revisions.
|
|
175
177
|
|
|
176
|
-
**Round-trip:** Element structure, child order, and text are preserved. The server may add **`db:order`**, **`db:xcitepath`**, **`xmlns:db`**. Attribute order and insignificant whitespace are **not** byte-stable—compare by DOM, not raw bytes.
|
|
178
|
+
**Round-trip:** Element structure, child order, and text are preserved. The server may add **`db:order`**, **`db:xcitepath`**, **`xmlns:db`**. Any app-specific structural metadata that must survive write→read (e.g. numbering aligned with an editor) must live **inside the stored XML** (or JSON metadata via **`addMeta`**); the server does not sync arbitrary sidecar fields. Attribute order and insignificant whitespace are **not** byte-stable—compare by DOM, not raw bytes.
|
|
177
179
|
|
|
178
180
|
## Minimal SPA editor recipe
|
|
179
181
|
|
|
@@ -184,7 +186,7 @@ client.setContext({ workspace: '', project_id: projectId });
|
|
|
184
186
|
/** Full document for the editor (all shredded children inlined). */
|
|
185
187
|
async function loadDocForEditor(id: string) {
|
|
186
188
|
return client.queryByIdentifierFull(id);
|
|
187
|
-
//
|
|
189
|
+
// Returns JSON array length 0 or 1: when present, index 0 is one fully assembled XML string (document order).
|
|
188
190
|
}
|
|
189
191
|
|
|
190
192
|
/** Sidebar / tree: shallow shell + one hierarchy level (two parallel requests). */
|
|
@@ -204,7 +206,7 @@ async function saveDirty(items: XmlDocumentBatchItem[]) {
|
|
|
204
206
|
}
|
|
205
207
|
```
|
|
206
208
|
|
|
207
|
-
**
|
|
209
|
+
**Batch save rules:** (1) Each intended root **`db:identifier`** appears as the **root** of **at most one** batch item per flush (**`duplicate_identifier_in_batch`**). (2) Do not ship a parent’s **full** subtree for a child id that is also its **own** batch row in the same request (**`parent_inlines_batch_member`**). Stubs **`db:stub="true"`** referencing another batch member are **allowed** and do not trigger (2). (3) **`is_top`** does not relax (1) or (2).
|
|
208
210
|
|
|
209
211
|
## JavaScript/TypeScript SDK (`@xcitedbs/client`)
|
|
210
212
|
|
|
@@ -326,13 +328,13 @@ interface XCiteDBClientOptions {
|
|
|
326
328
|
|
|
327
329
|
**XML Documents:**
|
|
328
330
|
- `writeXmlDocument(xml, options?)` — Store XML via JSON body (identifier inside XML). Deprecated alias: `writeDocumentJson`.
|
|
329
|
-
- `writeXmlDocumentsBatch(items)` — `POST /api/v1/documents/batch`; per-row `ok` / `error` / `code` (see shredding section for `409` batch conflicts)
|
|
331
|
+
- `writeXmlDocumentsBatch(items)` — `POST /api/v1/documents/batch`; per-row `ok` / `error` / `code` / optional `detail` (see shredding section for `409` batch conflicts)
|
|
330
332
|
- `writeXML(xml)` — Store raw XML with `Content-Type: application/xml`
|
|
331
333
|
- `importDocument(file, options?)` — `POST /api/v1/documents/import` (multipart `file`). Server converts DOCX, ODF, RTF, PDF, Markdown, AsciiDoc, or plain text into shredded XML. Optional `identifier` query override; optional `filename` for sniffing when not a `File`.
|
|
332
334
|
- `exportDocument(id, format?, options?)` — `GET /api/v1/documents/export` binary (`xml` | `docx` | `odt` | `pdf` | `txt` | `md` | `adoc`). Optional `strict` for text exports.
|
|
333
335
|
- `queryByIdentifier(id, flags?, filter?)` — Get document(s) by identifier
|
|
334
|
-
- `queryByIdentifierFull(id, filter?, pathFilter?)` — Same as `flags=FirstMatch,IncludeChildren` (editor load: full subtree)
|
|
335
|
-
- `queryByIdentifierShallow(id, filter?, pathFilter?)` — Same as `flags=NoChildren,KeepIndexNodes,FirstMatch` (skeleton:
|
|
336
|
+
- `queryByIdentifierFull(id, filter?, pathFilter?)` — Same as `flags=FirstMatch,IncludeChildren` (editor load: full subtree). Response array is **length 0 or 1**; the single string is the full document.
|
|
337
|
+
- `queryByIdentifierShallow(id, filter?, pathFilter?)` — Same as `flags=NoChildren,KeepIndexNodes,FirstMatch` (skeleton: **`db:stub="true"`** elements for shredded child slots; avoids full subtree)
|
|
336
338
|
- `listChildIdentifiers(parentPath?)` — Alias of `listIdentifierChildren`; next level of identifier hierarchy (pair with `queryByIdentifierShallow` for sidebars—`Promise.all` both if you want one round-trip client-side)
|
|
337
339
|
- `queryDocuments(query, flags?)` — List/filter documents
|
|
338
340
|
- `deleteDocument(identifier)` — Delete by identifier
|