@xcitedbs/client 0.2.21 → 0.2.23
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 +48 -1
- package/dist/client.js +233 -7
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +37 -0
- package/llms-full.txt +46 -5
- package/llms.txt +18 -2
- 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, Flags, JsonDocumentBatchItem, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LogEntry, MergeResult, PublishResult, WorkspaceInfo, MetaValue, PlatformRegisterResult, PolicySubjectInput, UnqueryResult, UnqueryTemplate, PolicyUpdateResponse, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredTriggerResponse, TriggerDefinition, StoredPolicyResponse, SubscriptionOptions, TagRecord, TextSearchQuery, TextSearchResult, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, 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, IdentifierChildNode, 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, 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;
|
|
@@ -93,6 +93,12 @@ export declare class XCiteDBClient {
|
|
|
93
93
|
private testHeaders;
|
|
94
94
|
private requestHeaders;
|
|
95
95
|
private request;
|
|
96
|
+
/**
|
|
97
|
+
* POST `multipart/form-data` without forcing JSON `Content-Type` (boundary is set by the runtime).
|
|
98
|
+
*/
|
|
99
|
+
private requestFormPost;
|
|
100
|
+
/** GET binary response (e.g. document export); errors are parsed as JSON when possible. */
|
|
101
|
+
private requestBinaryGet;
|
|
96
102
|
/** Developer Bearer refresh first, then app-user refresh (no API key refresh). */
|
|
97
103
|
private tryRefreshSessionAfter401;
|
|
98
104
|
private refreshAppUserNoRetry;
|
|
@@ -399,8 +405,16 @@ export declare class XCiteDBClient {
|
|
|
399
405
|
/** @deprecated Use {@link deleteBookmark}. */
|
|
400
406
|
deleteTag(name: string): Promise<void>;
|
|
401
407
|
compare(from: CompareRef, to: CompareRef, includeContent?: boolean): Promise<CompareResult>;
|
|
408
|
+
compare(from: CompareRef, to: CompareRef, options?: {
|
|
409
|
+
includeContent?: boolean;
|
|
410
|
+
matchStart?: string;
|
|
411
|
+
}): Promise<CompareResult>;
|
|
402
412
|
/** @deprecated Use {@link compare}. */
|
|
403
413
|
diff(from: DiffRef, to: DiffRef, includeContent?: boolean): Promise<DiffResult>;
|
|
414
|
+
diff(from: DiffRef, to: DiffRef, options?: {
|
|
415
|
+
includeContent?: boolean;
|
|
416
|
+
matchStart?: string;
|
|
417
|
+
}): Promise<DiffResult>;
|
|
404
418
|
publishWorkspace(targetWorkspace: string, sourceWorkspace: string, options?: {
|
|
405
419
|
message?: string;
|
|
406
420
|
autoResolve?: 'none' | 'source' | 'target';
|
|
@@ -440,6 +454,13 @@ export declare class XCiteDBClient {
|
|
|
440
454
|
message?: string;
|
|
441
455
|
autoResolve?: string;
|
|
442
456
|
}): Promise<Record<string, unknown>>;
|
|
457
|
+
/**
|
|
458
|
+
* Advance the user workspace fork to the current parent tip (`POST /api/v1/user-workspaces/{id}/rebase`).
|
|
459
|
+
* On overlap with local edits, returns **409** with `conflicts` (same shape as publish) unless `autoResolve` resolves it.
|
|
460
|
+
*/
|
|
461
|
+
rebaseUserWorkspace(id: string, options?: {
|
|
462
|
+
autoResolve?: 'none' | 'source' | 'target';
|
|
463
|
+
}): Promise<RebaseUserWorkspaceResult>;
|
|
443
464
|
/**
|
|
444
465
|
* Create `workspaceName` from {@link options.fromBranch} (or current context), run `fn` scoped to that workspace,
|
|
445
466
|
* create a checkpoint, then publish back unless {@link options.autoMerge} is `false`.
|
|
@@ -481,11 +502,37 @@ export declare class XCiteDBClient {
|
|
|
481
502
|
* Rows with `error === 'lock_conflict'` include `current_lock` (code **423** per row).
|
|
482
503
|
*/
|
|
483
504
|
writeXmlDocumentsBatch(items: XmlDocumentBatchItem[]): Promise<DocumentBatchResponse>;
|
|
505
|
+
/**
|
|
506
|
+
* Import a document (`POST /api/v1/documents/import`). Server converts DOCX, ODF, RTF, PDF, Markdown, AsciiDoc, or plain text
|
|
507
|
+
* to shredded XML. Field name must be `file` (multipart).
|
|
508
|
+
*/
|
|
509
|
+
importDocument(file: Blob | ArrayBuffer | Uint8Array, options?: ImportDocumentOptions): Promise<ImportDocumentResult>;
|
|
510
|
+
/**
|
|
511
|
+
* Export a document (`GET /api/v1/documents/export`). Returns binary bytes and response metadata.
|
|
512
|
+
*/
|
|
513
|
+
exportDocument(identifier: string, format?: DocumentExportFormat, options?: {
|
|
514
|
+
strict?: boolean;
|
|
515
|
+
}): Promise<ExportDocumentResult>;
|
|
484
516
|
/**
|
|
485
517
|
* @deprecated Use {@link writeXmlDocument}. This name was misleading: it writes **XML** via a JSON wrapper, not a JSON document.
|
|
486
518
|
*/
|
|
487
519
|
writeDocumentJson(xml: string, options?: WriteDocumentOptions): Promise<void>;
|
|
488
520
|
queryByIdentifier(identifier: string, flags?: Flags, filter?: string, pathFilter?: string): Promise<string[]>;
|
|
521
|
+
/**
|
|
522
|
+
* Shallow read: root element with inline leaves plus `db:N*` placeholders for shredded child slots
|
|
523
|
+
* (`flags=NoChildren,KeepIndexNodes,FirstMatch` on `GET /api/v1/documents/by-id`). Use with {@link listChildIdentifiers}
|
|
524
|
+
* or {@link queryByIdentifierWithChildren} for sidebar / AST navigation without loading the full subtree.
|
|
525
|
+
*/
|
|
526
|
+
queryByIdentifierShallow(identifier: string, filter?: string, pathFilter?: string): Promise<string[]>;
|
|
527
|
+
/** Alias of {@link listIdentifierChildren} — immediate child segments under `parentPath` (identifier hierarchy). */
|
|
528
|
+
listChildIdentifiers(parentPath?: string): Promise<ListIdentifierChildrenResult>;
|
|
529
|
+
/**
|
|
530
|
+
* Parallel shallow node + one level of identifier children (`GET /by-id` + `GET /identifier-children`).
|
|
531
|
+
*/
|
|
532
|
+
queryByIdentifierWithChildren(identifier: string, filter?: string, pathFilter?: string): Promise<{
|
|
533
|
+
node: string[];
|
|
534
|
+
children: IdentifierChildNode[];
|
|
535
|
+
}>;
|
|
489
536
|
queryDocuments(query: XCiteQuery, flags?: Flags, filter?: string, pathFilter?: string): Promise<string[]>;
|
|
490
537
|
deleteDocument(identifier: string): Promise<void>;
|
|
491
538
|
addIdentifier(identifier: string): Promise<boolean>;
|
package/dist/client.js
CHANGED
|
@@ -56,6 +56,24 @@ function buildQuery(params) {
|
|
|
56
56
|
const s = sp.toString();
|
|
57
57
|
return s ? `?${s}` : '';
|
|
58
58
|
}
|
|
59
|
+
/** Best-effort filename from `Content-Disposition` (attachment; filename="…"). */
|
|
60
|
+
function parseContentDispositionFilename(cd) {
|
|
61
|
+
if (!cd)
|
|
62
|
+
return undefined;
|
|
63
|
+
const mStar = cd.match(/filename\*=(?:UTF-8'')?([^;]+)/i);
|
|
64
|
+
if (mStar?.[1]) {
|
|
65
|
+
try {
|
|
66
|
+
return decodeURIComponent(mStar[1].trim().replace(/^"|"$/g, ''));
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return mStar[1].trim().replace(/^"|"$/g, '');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const m = cd.match(/filename\s*=\s*("?)([^";]+)\1/i);
|
|
73
|
+
if (m?.[2])
|
|
74
|
+
return m[2].trim();
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
59
77
|
function warnIfHttpOnTlsPort(baseUrl) {
|
|
60
78
|
try {
|
|
61
79
|
const u = new URL(baseUrl);
|
|
@@ -590,6 +608,122 @@ class XCiteDBClient {
|
|
|
590
608
|
this.notifySessionInvalidIfNeeded(path, 401);
|
|
591
609
|
throw new types_1.XCiteDBError('Request failed after retry', 401, null);
|
|
592
610
|
}
|
|
611
|
+
/**
|
|
612
|
+
* POST `multipart/form-data` without forcing JSON `Content-Type` (boundary is set by the runtime).
|
|
613
|
+
*/
|
|
614
|
+
async requestFormPost(path, form, opts) {
|
|
615
|
+
const no401Retry = opts?.no401Retry === true;
|
|
616
|
+
const suppressTestSessionHeader = opts?.suppressTestSessionHeader === true;
|
|
617
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
618
|
+
const url = joinUrl(this.baseUrl, path);
|
|
619
|
+
const outgoingRequestId = newClientRequestId();
|
|
620
|
+
const headers = {
|
|
621
|
+
...this.authHeaders(),
|
|
622
|
+
...this.contextHeaders(),
|
|
623
|
+
...(suppressTestSessionHeader ? {} : this.testHeaders()),
|
|
624
|
+
'X-Request-Id': outgoingRequestId,
|
|
625
|
+
};
|
|
626
|
+
const init = { method: 'POST', headers, body: form };
|
|
627
|
+
const sig = requestTimeoutSignal(this.requestTimeoutMs);
|
|
628
|
+
if (sig)
|
|
629
|
+
init.signal = sig;
|
|
630
|
+
let res;
|
|
631
|
+
try {
|
|
632
|
+
res = await fetch(url, init);
|
|
633
|
+
}
|
|
634
|
+
catch (e) {
|
|
635
|
+
const m = e instanceof Error ? e.message : 'Network error';
|
|
636
|
+
throw new types_1.XCiteDBError(m, 0, null, { clientRequestId: outgoingRequestId });
|
|
637
|
+
}
|
|
638
|
+
const text = await res.text();
|
|
639
|
+
let data;
|
|
640
|
+
try {
|
|
641
|
+
data = text ? JSON.parse(text) : null;
|
|
642
|
+
}
|
|
643
|
+
catch {
|
|
644
|
+
data = text;
|
|
645
|
+
}
|
|
646
|
+
if (res.ok) {
|
|
647
|
+
return data;
|
|
648
|
+
}
|
|
649
|
+
if (res.status === 401 &&
|
|
650
|
+
attempt === 0 &&
|
|
651
|
+
!no401Retry &&
|
|
652
|
+
(await this.tryRefreshSessionAfter401())) {
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
const msg = typeof data === 'object' && data !== null && 'message' in data
|
|
656
|
+
? String(data.message)
|
|
657
|
+
: res.statusText;
|
|
658
|
+
this.notifySessionInvalidIfNeeded(path, res.status);
|
|
659
|
+
throwForFailedHttp(res.status, path, data, msg || `HTTP ${res.status}`, res.headers.get('X-Request-Id') ?? undefined, res.headers.get('X-Client-Request-Id') ?? undefined);
|
|
660
|
+
}
|
|
661
|
+
this.notifySessionInvalidIfNeeded(path, 401);
|
|
662
|
+
throw new types_1.XCiteDBError('Request failed after retry', 401, null);
|
|
663
|
+
}
|
|
664
|
+
/** GET binary response (e.g. document export); errors are parsed as JSON when possible. */
|
|
665
|
+
async requestBinaryGet(path, opts) {
|
|
666
|
+
const no401Retry = opts?.no401Retry === true;
|
|
667
|
+
const suppressTestSessionHeader = opts?.suppressTestSessionHeader === true;
|
|
668
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
669
|
+
const url = joinUrl(this.baseUrl, path);
|
|
670
|
+
const outgoingRequestId = newClientRequestId();
|
|
671
|
+
const headers = {
|
|
672
|
+
...this.authHeaders(),
|
|
673
|
+
...this.contextHeaders(),
|
|
674
|
+
...(suppressTestSessionHeader ? {} : this.testHeaders()),
|
|
675
|
+
'X-Request-Id': outgoingRequestId,
|
|
676
|
+
};
|
|
677
|
+
const init = { method: 'GET', headers };
|
|
678
|
+
const sig = requestTimeoutSignal(this.requestTimeoutMs);
|
|
679
|
+
if (sig)
|
|
680
|
+
init.signal = sig;
|
|
681
|
+
let res;
|
|
682
|
+
try {
|
|
683
|
+
res = await fetch(url, init);
|
|
684
|
+
}
|
|
685
|
+
catch (e) {
|
|
686
|
+
const m = e instanceof Error ? e.message : 'Network error';
|
|
687
|
+
throw new types_1.XCiteDBError(m, 0, null, { clientRequestId: outgoingRequestId });
|
|
688
|
+
}
|
|
689
|
+
if (res.ok) {
|
|
690
|
+
const buf = new Uint8Array(await res.arrayBuffer());
|
|
691
|
+
const contentType = res.headers.get('Content-Type') ?? 'application/octet-stream';
|
|
692
|
+
const fn = parseContentDispositionFilename(res.headers.get('Content-Disposition')) ?? 'export.bin';
|
|
693
|
+
const rt = res.headers.get('X-XciteDB-Export-RoundTrip');
|
|
694
|
+
const roundTrip = rt === 'exact' || rt === 'lossy' ? rt : undefined;
|
|
695
|
+
const w = res.headers.get('X-XciteDB-Export-Warning');
|
|
696
|
+
return {
|
|
697
|
+
bytes: buf,
|
|
698
|
+
contentType,
|
|
699
|
+
filename: fn,
|
|
700
|
+
...(roundTrip ? { roundTrip } : {}),
|
|
701
|
+
...(w ? { warning: w } : {}),
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
if (res.status === 401 &&
|
|
705
|
+
attempt === 0 &&
|
|
706
|
+
!no401Retry &&
|
|
707
|
+
(await this.tryRefreshSessionAfter401())) {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
const text = await res.text();
|
|
711
|
+
let data;
|
|
712
|
+
try {
|
|
713
|
+
data = text ? JSON.parse(text) : null;
|
|
714
|
+
}
|
|
715
|
+
catch {
|
|
716
|
+
data = text;
|
|
717
|
+
}
|
|
718
|
+
const msg = typeof data === 'object' && data !== null && 'message' in data
|
|
719
|
+
? String(data.message)
|
|
720
|
+
: res.statusText;
|
|
721
|
+
this.notifySessionInvalidIfNeeded(path, res.status);
|
|
722
|
+
throwForFailedHttp(res.status, path, data, msg || `HTTP ${res.status}`, res.headers.get('X-Request-Id') ?? undefined, res.headers.get('X-Client-Request-Id') ?? undefined);
|
|
723
|
+
}
|
|
724
|
+
this.notifySessionInvalidIfNeeded(path, 401);
|
|
725
|
+
throw new types_1.XCiteDBError('Request failed after retry', 401, null);
|
|
726
|
+
}
|
|
593
727
|
/** Developer Bearer refresh first, then app-user refresh (no API key refresh). */
|
|
594
728
|
async tryRefreshSessionAfter401() {
|
|
595
729
|
if (this.accessToken && this.refreshToken) {
|
|
@@ -1221,16 +1355,35 @@ class XCiteDBClient {
|
|
|
1221
1355
|
async deleteTag(name) {
|
|
1222
1356
|
return this.deleteBookmark(name);
|
|
1223
1357
|
}
|
|
1224
|
-
async compare(from, to,
|
|
1225
|
-
|
|
1358
|
+
async compare(from, to, third) {
|
|
1359
|
+
let include_content = false;
|
|
1360
|
+
let match_start;
|
|
1361
|
+
if (typeof third === 'boolean') {
|
|
1362
|
+
include_content = third;
|
|
1363
|
+
}
|
|
1364
|
+
else if (third !== undefined && typeof third === 'object') {
|
|
1365
|
+
include_content = third.includeContent ?? false;
|
|
1366
|
+
match_start = third.matchStart;
|
|
1367
|
+
}
|
|
1368
|
+
const body = {
|
|
1226
1369
|
from,
|
|
1227
1370
|
to,
|
|
1228
|
-
include_content
|
|
1229
|
-
}
|
|
1371
|
+
include_content,
|
|
1372
|
+
};
|
|
1373
|
+
if (match_start !== undefined && match_start !== '') {
|
|
1374
|
+
body.match_start = this.isoPrefixId(match_start);
|
|
1375
|
+
}
|
|
1376
|
+
const r = await this.request('POST', '/api/v1/compare', body);
|
|
1377
|
+
if (r && typeof r === 'object' && typeof r.match_start === 'string' && r.match_start.length > 0) {
|
|
1378
|
+
r.match_start = this.isoUnprefixId(r.match_start);
|
|
1379
|
+
}
|
|
1380
|
+
return r;
|
|
1230
1381
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1382
|
+
async diff(from, to, third) {
|
|
1383
|
+
if (third === undefined || typeof third === 'boolean') {
|
|
1384
|
+
return this.compare(from, to, third);
|
|
1385
|
+
}
|
|
1386
|
+
return this.compare(from, to, third);
|
|
1234
1387
|
}
|
|
1235
1388
|
async publishWorkspace(targetWorkspace, sourceWorkspace, options) {
|
|
1236
1389
|
const body = {
|
|
@@ -1277,6 +1430,14 @@ class XCiteDBClient {
|
|
|
1277
1430
|
body.message = options.message;
|
|
1278
1431
|
return this.request('POST', `/api/v1/user-workspaces/${encodeURIComponent(id)}/publish`, body);
|
|
1279
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Advance the user workspace fork to the current parent tip (`POST /api/v1/user-workspaces/{id}/rebase`).
|
|
1435
|
+
* On overlap with local edits, returns **409** with `conflicts` (same shape as publish) unless `autoResolve` resolves it.
|
|
1436
|
+
*/
|
|
1437
|
+
async rebaseUserWorkspace(id, options) {
|
|
1438
|
+
const body = { auto_resolve: options?.autoResolve ?? 'none' };
|
|
1439
|
+
return this.request('POST', `/api/v1/user-workspaces/${encodeURIComponent(id)}/rebase`, body);
|
|
1440
|
+
}
|
|
1280
1441
|
/**
|
|
1281
1442
|
* Create `workspaceName` from {@link options.fromBranch} (or current context), run `fn` scoped to that workspace,
|
|
1282
1443
|
* create a checkpoint, then publish back unless {@link options.autoMerge} is `false`.
|
|
@@ -1354,6 +1515,49 @@ class XCiteDBClient {
|
|
|
1354
1515
|
}
|
|
1355
1516
|
return r;
|
|
1356
1517
|
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Import a document (`POST /api/v1/documents/import`). Server converts DOCX, ODF, RTF, PDF, Markdown, AsciiDoc, or plain text
|
|
1520
|
+
* to shredded XML. Field name must be `file` (multipart).
|
|
1521
|
+
*/
|
|
1522
|
+
async importDocument(file, options) {
|
|
1523
|
+
const form = new FormData();
|
|
1524
|
+
const blob = file instanceof Blob
|
|
1525
|
+
? file
|
|
1526
|
+
: file instanceof ArrayBuffer
|
|
1527
|
+
? new Blob([file], { type: 'application/octet-stream' })
|
|
1528
|
+
: new Blob([Uint8Array.from(file)], { type: 'application/octet-stream' });
|
|
1529
|
+
const uploadName = options?.filename ??
|
|
1530
|
+
(typeof File !== 'undefined' && file instanceof File ? file.name : 'upload.bin');
|
|
1531
|
+
form.append('file', blob, uploadName);
|
|
1532
|
+
const q = buildQuery({
|
|
1533
|
+
...(options?.identifier !== undefined && options.identifier !== ''
|
|
1534
|
+
? { identifier: this.isoPrefixId(options.identifier) }
|
|
1535
|
+
: {}),
|
|
1536
|
+
});
|
|
1537
|
+
const r = await this.requestFormPost(`/api/v1/documents/import${q}`, form);
|
|
1538
|
+
if (r && typeof r === 'object' && 'identifier' in r && typeof r.identifier === 'string') {
|
|
1539
|
+
r.identifier = this.isoUnprefixId(r.identifier);
|
|
1540
|
+
}
|
|
1541
|
+
return r;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Export a document (`GET /api/v1/documents/export`). Returns binary bytes and response metadata.
|
|
1545
|
+
*/
|
|
1546
|
+
async exportDocument(identifier, format = 'docx', options) {
|
|
1547
|
+
const q = buildQuery({
|
|
1548
|
+
identifier: this.isoPrefixId(identifier),
|
|
1549
|
+
format,
|
|
1550
|
+
strict: options?.strict ? '1' : undefined,
|
|
1551
|
+
});
|
|
1552
|
+
const r = await this.requestBinaryGet(`/api/v1/documents/export${q}`);
|
|
1553
|
+
return {
|
|
1554
|
+
bytes: r.bytes,
|
|
1555
|
+
contentType: r.contentType,
|
|
1556
|
+
filename: r.filename,
|
|
1557
|
+
...(r.roundTrip ? { roundTrip: r.roundTrip } : {}),
|
|
1558
|
+
...(r.warning ? { warning: r.warning } : {}),
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1357
1561
|
/**
|
|
1358
1562
|
* @deprecated Use {@link writeXmlDocument}. This name was misleading: it writes **XML** via a JSON wrapper, not a JSON document.
|
|
1359
1563
|
*/
|
|
@@ -1370,6 +1574,28 @@ class XCiteDBClient {
|
|
|
1370
1574
|
const rows = await this.request('GET', `/api/v1/documents/by-id${q}`);
|
|
1371
1575
|
return Array.isArray(rows) ? rows.map((x) => this.isoUnprefixId(String(x))) : rows;
|
|
1372
1576
|
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Shallow read: root element with inline leaves plus `db:N*` placeholders for shredded child slots
|
|
1579
|
+
* (`flags=NoChildren,KeepIndexNodes,FirstMatch` on `GET /api/v1/documents/by-id`). Use with {@link listChildIdentifiers}
|
|
1580
|
+
* or {@link queryByIdentifierWithChildren} for sidebar / AST navigation without loading the full subtree.
|
|
1581
|
+
*/
|
|
1582
|
+
async queryByIdentifierShallow(identifier, filter, pathFilter) {
|
|
1583
|
+
return this.queryByIdentifier(identifier, 'NoChildren,KeepIndexNodes,FirstMatch', filter, pathFilter);
|
|
1584
|
+
}
|
|
1585
|
+
/** Alias of {@link listIdentifierChildren} — immediate child segments under `parentPath` (identifier hierarchy). */
|
|
1586
|
+
async listChildIdentifiers(parentPath) {
|
|
1587
|
+
return this.listIdentifierChildren(parentPath);
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Parallel shallow node + one level of identifier children (`GET /by-id` + `GET /identifier-children`).
|
|
1591
|
+
*/
|
|
1592
|
+
async queryByIdentifierWithChildren(identifier, filter, pathFilter) {
|
|
1593
|
+
const [node, listed] = await Promise.all([
|
|
1594
|
+
this.queryByIdentifierShallow(identifier, filter, pathFilter),
|
|
1595
|
+
this.listIdentifierChildren(identifier),
|
|
1596
|
+
]);
|
|
1597
|
+
return { node, children: listed.children };
|
|
1598
|
+
}
|
|
1373
1599
|
async queryDocuments(query, flags, filter, pathFilter) {
|
|
1374
1600
|
const pq = this.isoPrefixQuery(query);
|
|
1375
1601
|
const params = {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { XCiteDBClient } from './client';
|
|
2
2
|
export { WebSocketSubscription } from './websocket';
|
|
3
|
-
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, Flags, JsonDocumentData, JsonDocumentBatchItem, IdentifierChildNode, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, AcquireLockOptions, LockConflictBody, LockExpiredBody, LockUnknownBody, MergeConflict, MergeResult, OAuthProviderInfo, OAuthProvidersResponse, OwnedTenantInfo, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspaceOrg, PlatformWorkspacesResponse, ProjectSearchSettings, ProjectSearchSettingsUpdate, ProjectDocConfResponse, PlatformDefaultDocConfResponse, LogEntry, MetaValue, PlatformRegisterResult, PolicyUpdateResponse, PublishConflict, PublishResult, 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';
|
|
3
|
+
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, 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
4
|
export { XCiteDBError, XCiteDBForbiddenError, XCiteDBNotFoundError, XCiteDBAuthError, XCiteDBLockConflictError, } from './types';
|
package/dist/types.d.ts
CHANGED
|
@@ -399,6 +399,31 @@ export interface WriteDocumentOptions {
|
|
|
399
399
|
is_top?: boolean;
|
|
400
400
|
compare_attributes?: boolean;
|
|
401
401
|
}
|
|
402
|
+
/** Supported source formats for `POST /api/v1/documents/import` (server detects from bytes / filename). */
|
|
403
|
+
export type DocumentImportFormat = 'docx' | 'odt' | 'rtf' | 'pdf' | 'txt' | 'md' | 'adoc';
|
|
404
|
+
/** JSON body on successful import (`201 Created`). */
|
|
405
|
+
export interface ImportDocumentResult {
|
|
406
|
+
identifier: string;
|
|
407
|
+
section_count: number;
|
|
408
|
+
source_format: string;
|
|
409
|
+
}
|
|
410
|
+
export interface ImportDocumentOptions {
|
|
411
|
+
/** Override root `db:identifier`; default is `/imported/<sanitized-filename>`. */
|
|
412
|
+
identifier?: string;
|
|
413
|
+
/** Original filename (helps sniff format when `File` is not available, e.g. Node `Blob` only). */
|
|
414
|
+
filename?: string;
|
|
415
|
+
}
|
|
416
|
+
/** `GET /api/v1/documents/export?format=…` */
|
|
417
|
+
export type DocumentExportFormat = 'xml' | 'docx' | 'odt' | 'pdf' | 'txt' | 'md' | 'adoc';
|
|
418
|
+
export interface ExportDocumentResult {
|
|
419
|
+
bytes: Uint8Array;
|
|
420
|
+
contentType: string;
|
|
421
|
+
filename: string;
|
|
422
|
+
/** Present for txt/md/adoc when server sends `X-XciteDB-Export-RoundTrip`. */
|
|
423
|
+
roundTrip?: 'exact' | 'lossy';
|
|
424
|
+
/** From `X-XciteDB-Export-Warning` when present. */
|
|
425
|
+
warning?: string;
|
|
426
|
+
}
|
|
402
427
|
/** One row in `POST /api/v1/documents/batch` or `POST /api/v1/json-documents/batch` response `results`. */
|
|
403
428
|
export interface DocumentBatchResultRow {
|
|
404
429
|
index: number;
|
|
@@ -835,6 +860,8 @@ export interface CompareResult {
|
|
|
835
860
|
date_key?: string;
|
|
836
861
|
};
|
|
837
862
|
total_changes: number;
|
|
863
|
+
/** Echo of request `match_start` when path-scoped compare was used. */
|
|
864
|
+
match_start?: string;
|
|
838
865
|
}
|
|
839
866
|
/** @deprecated Use {@link CompareResult}. */
|
|
840
867
|
export type DiffResult = CompareResult;
|
|
@@ -857,6 +884,16 @@ export interface PublishResult {
|
|
|
857
884
|
}
|
|
858
885
|
/** @deprecated Use {@link PublishResult}. */
|
|
859
886
|
export type MergeResult = PublishResult;
|
|
887
|
+
/** `POST /api/v1/user-workspaces/{id}/rebase` */
|
|
888
|
+
export interface RebaseUserWorkspaceResult {
|
|
889
|
+
status: 'completed' | 'conflicts';
|
|
890
|
+
message?: string;
|
|
891
|
+
old_from_date_key?: string;
|
|
892
|
+
new_from_date_key?: string;
|
|
893
|
+
conflicts?: PublishConflict[];
|
|
894
|
+
auto_mergeable?: string[];
|
|
895
|
+
would_expose?: string[];
|
|
896
|
+
}
|
|
860
897
|
export type XCiteDBErrorExtras = {
|
|
861
898
|
reason?: string;
|
|
862
899
|
policyId?: string;
|
package/llms-full.txt
CHANGED
|
@@ -35,7 +35,7 @@ Before reading the full reference, note these critical differences from typical
|
|
|
35
35
|
- **Write at a specific date:** Set `X-Date` / `context.date` and write — every dated write is a **temporal revision**; no workspace or checkpoint required.
|
|
36
36
|
- **Read as-of a date:** Set `X-Date` and read; the engine returns the revision at or before that instant.
|
|
37
37
|
- **Isolated editing (draft → publish):** Create a **workspace**, edit, then **publish** to the target timeline; optional **checkpoints** for named snapshots.
|
|
38
|
-
- **App-user user workspaces (`_uw/<owner>/<slug>`):** **`GET/POST /api/v1/user-workspaces`**, grants, publish — see repository **`web/src/docs/content/user-workspaces.md`**.
|
|
38
|
+
- **App-user user workspaces (`_uw/<owner>/<slug>`):** **`GET/POST /api/v1/user-workspaces`**, grants, publish, **rebase** — see repository **`web/src/docs/content/user-workspaces.md`**.
|
|
39
39
|
- **Audit trail:** Checkpoints carry messages and affected identifiers; **bookmarks** name a checkpoint.
|
|
40
40
|
- **Undo a batch:** **Revert** to a prior checkpoint on that workspace.
|
|
41
41
|
|
|
@@ -434,6 +434,16 @@ The identifier is extracted from the `db:identifier` attribute in the root XML e
|
|
|
434
434
|
|
|
435
435
|
Query parameters: `identifier` (required), `flags` (optional: `FirstMatch`, `IncludeChildren`, `NoChildren`, `KeepIndexNodes`), `filter`, `path_filter`.
|
|
436
436
|
|
|
437
|
+
### Shallow node + subtree navigation
|
|
438
|
+
|
|
439
|
+
- **`flags=NoChildren,KeepIndexNodes,FirstMatch`**: returns the matching node with inline leaf content plus **`db:N1`**, **`db:N2`**, … placeholders for shredded child slots (avoids loading the full deep subtree in one response).
|
|
440
|
+
- Combine with **`GET /api/v1/documents/identifier-children?parent_path=…`** for the next level of hierarchy (`segment`, `full_path`, `is_identifier`, `has_children`).
|
|
441
|
+
- **JavaScript SDK:** `queryByIdentifierShallow(id)`, `listChildIdentifiers(parentPath?)`, `queryByIdentifierWithChildren(id)` (shallow XML + children in parallel).
|
|
442
|
+
|
|
443
|
+
### Standalone subtree write (shredded model)
|
|
444
|
+
|
|
445
|
+
You may `POST /api/v1/documents` with a root element whose `db:identifier` is a nested path (e.g. `/spaces/u/docs/doc1/sec-1`) without re-posting the parent document: the engine writes that subtree only and updates the identifier hierarchy index for the parent automatically. Keep `is_top: true` (default) on the write.
|
|
446
|
+
|
|
437
447
|
## Delete document
|
|
438
448
|
|
|
439
449
|
**`DELETE /api/v1/documents/by-id?identifier=/book/ch1`**
|
|
@@ -526,7 +536,7 @@ Returns `{ identifiers: string[], total, offset, limit }`.
|
|
|
526
536
|
|
|
527
537
|
## Export document
|
|
528
538
|
|
|
529
|
-
**`GET /api/v1/documents/export?
|
|
539
|
+
**`GET /api/v1/documents/export?identifier=/book/ch1&format=...`**
|
|
530
540
|
|
|
531
541
|
## Export provision
|
|
532
542
|
|
|
@@ -847,6 +857,22 @@ Returns `{ status: "completed"|"conflicts", checkpoint?, commit?, merged_identif
|
|
|
847
857
|
|
|
848
858
|
---
|
|
849
859
|
|
|
860
|
+
# App-user workspaces (`/api/v1/user-workspaces`)
|
|
861
|
+
|
|
862
|
+
Per-user draft branches (`_uw/<owner>/<slug>`). See also **`web/src/docs/content/user-workspaces.md`**.
|
|
863
|
+
|
|
864
|
+
## Rebase user workspace
|
|
865
|
+
|
|
866
|
+
**`POST /api/v1/user-workspaces/{id}/rebase`**
|
|
867
|
+
|
|
868
|
+
```json
|
|
869
|
+
{ "auto_resolve": "none" }
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
Advances the workspace branch fork metadata to the **current tip** of its parent branch. Returns **`200`** with `{ status: "completed", message?, old_from_date_key, new_from_date_key, would_expose[], auto_mergeable[], conflicts: [] }`, or **`409`** with `{ status: "conflicts", conflicts: [...], auto_mergeable?, would_expose? }` when the same identifiers changed on both parent and workspace since the fork (same conflict shape as workspace publish).
|
|
873
|
+
|
|
874
|
+
---
|
|
875
|
+
|
|
850
876
|
# Checkpoints, bookmarks & compare
|
|
851
877
|
|
|
852
878
|
## Create checkpoint
|
|
@@ -896,13 +922,16 @@ Returns `{ checkpoints: [...], commits: [...], total, branch }` (mirrors).
|
|
|
896
922
|
{
|
|
897
923
|
"from": { "branch": "", "date": "2024-01-15T00:00:00" },
|
|
898
924
|
"to": { "branch": "feature-x" },
|
|
899
|
-
"include_content": true
|
|
925
|
+
"include_content": true,
|
|
926
|
+
"match_start": "/spaces/u/docs/doc1"
|
|
900
927
|
}
|
|
901
928
|
```
|
|
902
929
|
|
|
930
|
+
Optional **`match_start`**: when set, only identifiers equal to that path or under it (prefix + `/`) are included in **`changes`** (tenant-wide noise is dropped).
|
|
931
|
+
|
|
903
932
|
(Deprecated: **`POST /api/v1/diff`**; `date_key` still accepted internally but prefer **`date`**.)
|
|
904
933
|
|
|
905
|
-
Returns `{ changes: [{ identifier, action: "added"|"modified"|"deleted", from_content?, to_content? }], total_changes }
|
|
934
|
+
Returns `{ changes: [{ identifier, action: "added"|"modified"|"deleted", from_content?, to_content? }], total_changes, match_start? }` ( **`match_start`** echoed when the filter was used).
|
|
906
935
|
|
|
907
936
|
---
|
|
908
937
|
|
|
@@ -1506,7 +1535,12 @@ interface DatabaseContext {
|
|
|
1506
1535
|
### XML Documents
|
|
1507
1536
|
- `writeXmlDocument(xml, options?)` → `void` — XML via JSON body (recommended). Deprecated: `writeDocumentJson`.
|
|
1508
1537
|
- `writeXML(xml)` → `void` — Raw XML body
|
|
1538
|
+
- `importDocument(file, options?)` → `ImportDocumentResult` — multipart `POST /api/v1/documents/import`
|
|
1539
|
+
- `exportDocument(identifier, format?, options?)` → `ExportDocumentResult` — binary `GET /api/v1/documents/export`
|
|
1509
1540
|
- `queryByIdentifier(identifier, flags?, filter?, pathFilter?)` → `string[]`
|
|
1541
|
+
- `queryByIdentifierShallow(identifier, filter?, pathFilter?)` → `string[]` — `NoChildren,KeepIndexNodes,FirstMatch`
|
|
1542
|
+
- `listChildIdentifiers(parentPath?)` → `ListIdentifierChildrenResult` — alias of `listIdentifierChildren`
|
|
1543
|
+
- `queryByIdentifierWithChildren(identifier, filter?, pathFilter?)` → `{ node, children }`
|
|
1510
1544
|
- `queryDocuments(query: XCiteQuery, flags?, filter?, pathFilter?)` → `string[]`
|
|
1511
1545
|
- `deleteDocument(identifier)` → `void`
|
|
1512
1546
|
- `listIdentifiers(query: XCiteQuery)` → `ListIdentifiersResult`
|
|
@@ -1544,6 +1578,13 @@ interface DatabaseContext {
|
|
|
1544
1578
|
- `publishWorkspace(targetWorkspace, sourceWorkspace, options?)` → `PublishResult`
|
|
1545
1579
|
- **Deprecated:** `withBranch`, `createBranch`, `listBranches`, `getBranch`, `deleteBranch`, `mergeBranch` (same HTTP behavior)
|
|
1546
1580
|
|
|
1581
|
+
### App-user user workspaces (`_uw/…`)
|
|
1582
|
+
- `listUserWorkspaces()` → `{ user_workspaces: unknown[] }`
|
|
1583
|
+
- `createUserWorkspace(name, options?)` → `Record<string, unknown>`
|
|
1584
|
+
- `getUserWorkspace(id)` / `deleteUserWorkspace(id)` / `addUserWorkspaceGrant(id, body)` / `removeUserWorkspaceGrant(id, body)`
|
|
1585
|
+
- `publishUserWorkspace(id, options?)` → `PublishResult`-shaped JSON
|
|
1586
|
+
- `rebaseUserWorkspace(id, options?)` → `RebaseUserWorkspaceResult` — advances fork onto parent tip; **409** + `conflicts` on overlap (optional `autoResolve`: `none` | `source` | `target`)
|
|
1587
|
+
|
|
1547
1588
|
### Checkpoints
|
|
1548
1589
|
- `createCheckpoint(message, author?)` → `CheckpointRecord`
|
|
1549
1590
|
- `listCheckpoints(options?)` → `{ checkpoints, total, branch }` (wire JSON may also include `commits` mirror)
|
|
@@ -1560,7 +1601,7 @@ interface DatabaseContext {
|
|
|
1560
1601
|
- **Deprecated:** `createTag`, `listTags`, `getTag`, `deleteTag`
|
|
1561
1602
|
|
|
1562
1603
|
### Compare
|
|
1563
|
-
- `compare(from: CompareRef, to: CompareRef, includeContent?)` → `CompareResult`
|
|
1604
|
+
- `compare(from: CompareRef, to: CompareRef, includeContent?)` or `compare(from, to, { includeContent?, matchStart? })` → `CompareResult`
|
|
1564
1605
|
- **Deprecated:** `diff(from: DiffRef, …)` — alias of `compare`
|
|
1565
1606
|
|
|
1566
1607
|
### Locks
|
package/llms.txt
CHANGED
|
@@ -158,6 +158,10 @@ When you build a backend that calls XCiteDB on behalf of users:
|
|
|
158
158
|
- **Metadata `mode` and arrays.** **`POST /api/v1/meta`** uses **`mode`**: default **`set`** writes or replaces at `path` (arrays are replaced in range; excess old indices cleared); **`append`** appends array elements after existing ones at `path`. Optional **`overwrite: true`** clears metadata under `path` before writing. JavaScript: **`appendMeta`** or **`addMeta(..., { mode: 'append' })`**; Python/C++: **`append_meta`** or **`add_meta`** with **`mode`** / **`overwrite`** (see SDK sections below).
|
|
159
159
|
- **Prefer dictionary-style objects.** **Shredded** JSON metadata is stored in **fragment-level** keys (e.g. per field name). **Object maps** get per-field storage; when an object accumulates enough distinct field names (server default threshold **32**), XCiteDB switches automatically to **dictionary storage** (`{*}` plus per-field keys) for efficient indexed access. For lookup-heavy or wide records, use **`{ "key": value, ... }`** shapes (or one document per logical row) rather than opaque arrays when you need keyed reads.
|
|
160
160
|
|
|
161
|
+
## XML subtree writes (shredded model)
|
|
162
|
+
|
|
163
|
+
- **Standalone subtree root.** Because XCiteDB shreds XML per identifier, you can `writeXmlDocument('<sec db:identifier="/spaces/u/docs/doc1/sec-1">…</sec>')` and the engine writes only that subtree — you do **not** need to re-send the parent document. The parent's children index (`id_hier`) is updated automatically. Keep `is_top: true` (default) on `POST /api/v1/documents` even when the `db:identifier` is nested under another path. Use `compare_attributes: true` only when you need attribute-level diffing for triggers.
|
|
164
|
+
|
|
161
165
|
## JavaScript/TypeScript SDK (`@xcitedbs/client`)
|
|
162
166
|
|
|
163
167
|
Install: `npm install @xcitedbs/client`
|
|
@@ -191,6 +195,11 @@ await client.writeXmlDocument(
|
|
|
191
195
|
'<chapter db:identifier="/manual/v1/intro"><title>Introduction</title></chapter>'
|
|
192
196
|
);
|
|
193
197
|
|
|
198
|
+
// Import DOCX/PDF (etc.) server-side — shredded into XML (`POST /api/v1/documents/import`, multipart field `file`)
|
|
199
|
+
// const fileBlob = …; // Blob from <input type="file"> or fetch
|
|
200
|
+
// await client.importDocument(fileBlob, { identifier: '/manual/imported/spec', filename: 'spec.docx' });
|
|
201
|
+
// const out = await client.exportDocument('/manual/imported/spec', 'docx'); // bytes in `out.bytes`
|
|
202
|
+
|
|
194
203
|
// Write a JSON document
|
|
195
204
|
await client.writeJsonDocument('app.settings', { theme: 'dark', locale: 'en' });
|
|
196
205
|
|
|
@@ -274,7 +283,12 @@ interface XCiteDBClientOptions {
|
|
|
274
283
|
**XML Documents:**
|
|
275
284
|
- `writeXmlDocument(xml, options?)` — Store XML via JSON body (identifier inside XML). Deprecated alias: `writeDocumentJson`.
|
|
276
285
|
- `writeXML(xml)` — Store raw XML with `Content-Type: application/xml`
|
|
286
|
+
- `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`.
|
|
287
|
+
- `exportDocument(id, format?, options?)` — `GET /api/v1/documents/export` binary (`xml` | `docx` | `odt` | `pdf` | `txt` | `md` | `adoc`). Optional `strict` for text exports.
|
|
277
288
|
- `queryByIdentifier(id, flags?, filter?)` — Get document(s) by identifier
|
|
289
|
+
- `queryByIdentifierShallow(id, filter?, pathFilter?)` — Same as `flags=NoChildren,KeepIndexNodes,FirstMatch` (skeleton: placeholders `db:N*` for shredded slots; avoids full subtree)
|
|
290
|
+
- `listChildIdentifiers(parentPath?)` — Alias of `listIdentifierChildren`; next level of identifier hierarchy
|
|
291
|
+
- `queryByIdentifierWithChildren(id, filter?, pathFilter?)` — `Promise.all` of shallow node + `identifier-children` for one expansion step
|
|
278
292
|
- `queryDocuments(query, flags?)` — List/filter documents
|
|
279
293
|
- `deleteDocument(identifier)` — Delete by identifier
|
|
280
294
|
- `listIdentifiers(query)` — List known identifiers with pagination
|
|
@@ -299,12 +313,12 @@ interface XCiteDBClientOptions {
|
|
|
299
313
|
- `listWorkspaces()` — List workspaces
|
|
300
314
|
- `publishWorkspace(target, source, options?)` — Publish workspace changes to a target timeline
|
|
301
315
|
- `deleteWorkspace(name)` — Delete workspace
|
|
302
|
-
- `listUserWorkspaces()` / `createUserWorkspace(name, options?)` / `getUserWorkspace(id)` / `deleteUserWorkspace(id)` / `addUserWorkspaceGrant(id, body)` / `removeUserWorkspaceGrant(id, body)` / `publishUserWorkspace(id, options?)` — App-user **`_uw/…`** workspaces
|
|
316
|
+
- `listUserWorkspaces()` / `createUserWorkspace(name, options?)` / `getUserWorkspace(id)` / `deleteUserWorkspace(id)` / `addUserWorkspaceGrant(id, body)` / `removeUserWorkspaceGrant(id, body)` / `publishUserWorkspace(id, options?)` / `rebaseUserWorkspace(id, options?)` — App-user **`_uw/…`** workspaces (`rebase` advances the fork onto the parent tip; **409** + `conflicts` on overlap, like publish)
|
|
303
317
|
- `createCheckpoint(message, author?)` — Named snapshot of current state
|
|
304
318
|
- `listCheckpoints(options?)` — List checkpoints
|
|
305
319
|
- `revertToCheckpoint(checkpointId)` — Revert workspace to a prior checkpoint
|
|
306
320
|
- `applyCheckpoint(checkpointId, message?)` — Apply another checkpoint’s changes here
|
|
307
|
-
- `compare(from, to, includeContent?)` — Compare revisions
|
|
321
|
+
- `compare(from, to, includeContent?)` or `compare(from, to, { includeContent?, matchStart? })` — Compare revisions; optional **`matchStart`** restricts results to that identifier and descendants (same as document `match_start` query semantics)
|
|
308
322
|
- `createBookmark(name, checkpointId, message?)` — Bookmark a checkpoint
|
|
309
323
|
- `listBookmarks()` / `deleteBookmark(name)` — Manage bookmarks
|
|
310
324
|
- **Deprecated aliases:** `withBranch`, `createBranch`, `listBranches`, `mergeBranch`, `deleteBranch`, `createCommit`, `listCommits`, `rollbackToCommit`, `cherryPick`, `diff`, `createTag`, `listTags`, `deleteTag` (same HTTP behavior)
|
|
@@ -369,6 +383,8 @@ When calling `queryByIdentifier` or `queryDocuments`, the `flags` parameter cont
|
|
|
369
383
|
- `'NoChildren'` — Exclude children
|
|
370
384
|
- `'KeepIndexNodes'` — Include index/structural nodes
|
|
371
385
|
|
|
386
|
+
**Sidebar / AST navigation:** combine **`'NoChildren,KeepIndexNodes,FirstMatch'`** (or `queryByIdentifierShallow`) with **`listChildIdentifiers`** / **`listIdentifierChildren`** so each expansion is one shallow XML read plus one child list, instead of `IncludeChildren` loading the entire subtree.
|
|
387
|
+
|
|
372
388
|
### Errors
|
|
373
389
|
|
|
374
390
|
All API errors throw `XCiteDBError` with `.status` (HTTP code) and `.body` (parsed response). Common codes: `401` unauthenticated, `403` forbidden by policy or RBAC, `404` not found, `409` conflict (lock), `422` validation, `423` project encrypted and locked, `429` rate limited. Many **ABAC** denials return `403` with `"message":"Forbidden"` plus optional **`policy_id`** and **`hint`** (check JWT `tenant_id` vs `project:` group middle segment).
|