@xcitedbs/client 0.2.6 → 0.2.7
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 +141 -2
- package/dist/client.js +139 -0
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +38 -2
- package/llms-full.txt +208 -8
- package/llms.txt +20 -0
- 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, CommitRecord, DatabaseContext, DiffRef, DiffResult, Flags, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, LogEntry, MergeResult, MetaValue, PlatformRegisterResult, PolicySubjectInput, UnqueryResult, PolicyUpdateResponse, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredTriggerResponse, TriggerDefinition, StoredPolicyResponse, SubscriptionOptions, TagRecord, TextSearchQuery, TextSearchResult, OAuthProvidersResponse, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspacesResponse, TokenPair, UserInfo, ApiKeyInfo, WriteDocumentOptions, CreateTestSessionOptions, XCiteDBClientOptions, XCiteQuery } from './types';
|
|
1
|
+
import { AccessCheckResult, AppAuthConfig, AppEmailConfig, AppEmailTemplates, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, BranchInfo, CommitRecord, DatabaseContext, DiffRef, DiffResult, Flags, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, LogEntry, MergeResult, MetaValue, PlatformRegisterResult, PolicySubjectInput, UnqueryResult, UnqueryTemplate, PolicyUpdateResponse, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredTriggerResponse, TriggerDefinition, StoredPolicyResponse, SubscriptionOptions, TagRecord, TextSearchQuery, TextSearchResult, OAuthProvidersResponse, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspacesResponse, TokenPair, UserInfo, ApiKeyInfo, WriteDocumentOptions, CreateTestSessionOptions, XCiteDBClientOptions, XCiteQuery } from './types';
|
|
2
2
|
import { WebSocketSubscription } from './websocket';
|
|
3
3
|
export declare class XCiteDBClient {
|
|
4
4
|
private baseUrl;
|
|
@@ -129,17 +129,131 @@ export declare class XCiteDBClient {
|
|
|
129
129
|
deleteAppUser(userId: string): Promise<void>;
|
|
130
130
|
updateAppUserGroups(userId: string, groups: string[]): Promise<void>;
|
|
131
131
|
updateAppUserStatus(userId: string, status: 'active' | 'disabled' | 'pending_verification'): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Create an ABAC policy (`POST /api/v1/security/policies`). Requires admin/editor role.
|
|
134
|
+
* Use `conditions.expression` for attribute-based rules (same predicate syntax as Unquery `?` conditions).
|
|
135
|
+
* Policy actions: `read`, `write`, `delete`, `list`, `meta:read`, `meta:write`, `unquery`.
|
|
136
|
+
*
|
|
137
|
+
* @example Tenant isolation: first path segment must equal app-user attribute `tenant_code`.
|
|
138
|
+
* ```ts
|
|
139
|
+
* await client.createPolicy('tenant_isolation', {
|
|
140
|
+
* effect: 'allow',
|
|
141
|
+
* priority: 100,
|
|
142
|
+
* subjects: { type: 'app_user' },
|
|
143
|
+
* actions: ['read'],
|
|
144
|
+
* resources: { identifiers: [{ match_start: '/' }] },
|
|
145
|
+
* conditions: { expression: 'resource.path[0] = subject.attr.tenant_code' },
|
|
146
|
+
* });
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @example Deny viewers write access under `/admin/`.
|
|
150
|
+
* ```ts
|
|
151
|
+
* await client.createPolicy('deny_viewers_admin', {
|
|
152
|
+
* effect: 'deny',
|
|
153
|
+
* priority: 10,
|
|
154
|
+
* subjects: { type: 'app_user', groups: ['viewers'] },
|
|
155
|
+
* resources: { identifiers: [{ match_start: '/admin/' }] },
|
|
156
|
+
* actions: ['write', 'delete', 'meta:write'],
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*
|
|
160
|
+
* @example Branch-only rule via `conditions.branches`.
|
|
161
|
+
* ```ts
|
|
162
|
+
* await client.createPolicy('staging_only', {
|
|
163
|
+
* effect: 'allow',
|
|
164
|
+
* priority: 50,
|
|
165
|
+
* subjects: { type: 'app_user', groups: ['qa'] },
|
|
166
|
+
* actions: ['read', 'write'],
|
|
167
|
+
* resources: { identifiers: [{ match_start: '/staging/' }] },
|
|
168
|
+
* conditions: { branches: ['stg', 'stg*'] },
|
|
169
|
+
* });
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
132
172
|
createPolicy(policyId: string, policy: SecurityPolicy): Promise<StoredPolicyResponse>;
|
|
133
173
|
listPolicies(): Promise<Record<string, SecurityPolicy>>;
|
|
134
174
|
getPolicy(policyId: string): Promise<StoredPolicyResponse>;
|
|
135
175
|
updatePolicy(policyId: string, policy: SecurityPolicy): Promise<PolicyUpdateResponse>;
|
|
136
176
|
deletePolicy(policyId: string): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Create or update a trigger (`POST /api/v1/triggers`). Definitions live under `/_xcitedb/triggers`.
|
|
179
|
+
* After matching events, the server runs `action.unquery` over `action.query` and writes JSON to
|
|
180
|
+
* `action.meta_path` on `action.target_identifier` (use `"$trigger_identifier"` for the firing doc).
|
|
181
|
+
* Unquery can use `$trigger_identifier`, `$trigger_meta_path`, `$trigger_operation`, `$trigger_value`.
|
|
182
|
+
*
|
|
183
|
+
* @example On meta change under `/projects/`, append a snapshot entry to an index document.
|
|
184
|
+
* ```ts
|
|
185
|
+
* await client.upsertTrigger('project_meta_index', {
|
|
186
|
+
* event: 'meta_changed',
|
|
187
|
+
* match: {
|
|
188
|
+
* identifiers: [{ match_start: '/projects/' }],
|
|
189
|
+
* match_meta_path: 'status',
|
|
190
|
+
* },
|
|
191
|
+
* action: {
|
|
192
|
+
* query: { match: '$trigger_identifier' },
|
|
193
|
+
* unquery: { lastId: '$trigger_identifier', path: '$trigger_meta_path' },
|
|
194
|
+
* target_identifier: '/indexes/project_meta',
|
|
195
|
+
* meta_path: 'entries',
|
|
196
|
+
* mode: 'append',
|
|
197
|
+
* },
|
|
198
|
+
* });
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* @example On document write, write a computed summary onto the same identifier's meta.
|
|
202
|
+
* ```ts
|
|
203
|
+
* await client.upsertTrigger('doc_written_summary', {
|
|
204
|
+
* event: 'document_written',
|
|
205
|
+
* match: { identifiers: [{ match_start: '/articles/' }] },
|
|
206
|
+
* action: {
|
|
207
|
+
* query: { match: '$trigger_identifier' },
|
|
208
|
+
* unquery: { id: '$identifier', nodeCount: '$count' },
|
|
209
|
+
* target_identifier: '$trigger_identifier',
|
|
210
|
+
* meta_path: 'stats',
|
|
211
|
+
* },
|
|
212
|
+
* });
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
137
215
|
upsertTrigger(triggerId: string, trigger: TriggerDefinition): Promise<StoredTriggerResponse>;
|
|
138
216
|
listTriggers(): Promise<Record<string, TriggerDefinition>>;
|
|
139
217
|
getTrigger(name: string): Promise<StoredTriggerResponse>;
|
|
140
218
|
deleteTrigger(name: string): Promise<void>;
|
|
219
|
+
/**
|
|
220
|
+
* Dry-run access check (`POST /api/v1/security/check`). Returns `effect` and optional `matched_policy_id`.
|
|
221
|
+
* Useful for debugging policies. Actions: `read`, `write`, `delete`, `list`, `meta:read`, `meta:write`, `unquery`.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const r = await client.checkAccess(
|
|
226
|
+
* {
|
|
227
|
+
* type: 'app_user',
|
|
228
|
+
* user_id: 'u1',
|
|
229
|
+
* email: 'alice@example.com',
|
|
230
|
+
* groups: ['editors'],
|
|
231
|
+
* role: 'app_user',
|
|
232
|
+
* attributes: { tenant_code: 'acme', level: 5 },
|
|
233
|
+
* },
|
|
234
|
+
* '/acme/reports/q1',
|
|
235
|
+
* 'read',
|
|
236
|
+
* undefined,
|
|
237
|
+
* 'main'
|
|
238
|
+
* );
|
|
239
|
+
* console.log(r.effect, r.matched_policy_id);
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
141
242
|
checkAccess(subject: PolicySubjectInput, identifier: string, action: string, metaPath?: string, branch?: string): Promise<AccessCheckResult>;
|
|
142
243
|
getSecurityConfig(): Promise<SecurityConfig>;
|
|
244
|
+
/**
|
|
245
|
+
* Update tenant security defaults (`PUT /api/v1/security/config`). When ABAC is enabled, pair
|
|
246
|
+
* `app_user_default_effect: 'deny'` with explicit allow policies for least privilege.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* await client.updateSecurityConfig({
|
|
251
|
+
* app_user_default_effect: 'deny',
|
|
252
|
+
* default_effect: 'allow',
|
|
253
|
+
* developer_bypass: true,
|
|
254
|
+
* });
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
143
257
|
updateSecurityConfig(config: Partial<SecurityConfig>): Promise<void>;
|
|
144
258
|
createBranch(name: string, fromBranch?: string, fromDate?: string): Promise<void>;
|
|
145
259
|
deleteBranch(name: string): Promise<void>;
|
|
@@ -230,7 +344,32 @@ export declare class XCiteDBClient {
|
|
|
230
344
|
acquireLock(identifier: string, expires?: number): Promise<LockInfo>;
|
|
231
345
|
releaseLock(identifier: string, lockId: string): Promise<boolean>;
|
|
232
346
|
findLocks(identifier: string): Promise<LockInfo[]>;
|
|
233
|
-
|
|
347
|
+
/**
|
|
348
|
+
* Run Unquery (`POST /api/v1/unquery`): declarative analytics over documents matching `query`.
|
|
349
|
+
* The `unquery` argument is a JSON template; keys are output fields, string values are expressions.
|
|
350
|
+
*
|
|
351
|
+
* @example Project a meta field into a result key.
|
|
352
|
+
* ```ts
|
|
353
|
+
* const out = await client.unquery<{ tag: string }>(
|
|
354
|
+
* { match_start: '/manual/' },
|
|
355
|
+
* { title: 'chapter_title' }
|
|
356
|
+
* );
|
|
357
|
+
* ```
|
|
358
|
+
*
|
|
359
|
+
* @example Count matching documents.
|
|
360
|
+
* ```ts
|
|
361
|
+
* const out = await client.unquery<{ total: number }>({ match_start: '/orders/' }, { total: '$count' });
|
|
362
|
+
* ```
|
|
363
|
+
*
|
|
364
|
+
* @example XPath from XML (string value must escape quotes for TS).
|
|
365
|
+
* ```ts
|
|
366
|
+
* const out = await client.unquery<{ heading: string }>(
|
|
367
|
+
* { match: '/book/ch1' },
|
|
368
|
+
* { heading: '$xpath("//h1")' }
|
|
369
|
+
* );
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
unquery<T = UnqueryResult>(query: XCiteQuery, unquery: UnqueryTemplate): Promise<T>;
|
|
234
373
|
search(q: TextSearchQuery): Promise<TextSearchResult>;
|
|
235
374
|
reindex(): Promise<{
|
|
236
375
|
status: string;
|
package/dist/client.js
CHANGED
|
@@ -502,6 +502,46 @@ class XCiteDBClient {
|
|
|
502
502
|
await this.request('PUT', `/api/v1/app/users/${encodeURIComponent(userId)}/status`, { status });
|
|
503
503
|
}
|
|
504
504
|
// --- Security policies (developer admin/editor) ---
|
|
505
|
+
/**
|
|
506
|
+
* Create an ABAC policy (`POST /api/v1/security/policies`). Requires admin/editor role.
|
|
507
|
+
* Use `conditions.expression` for attribute-based rules (same predicate syntax as Unquery `?` conditions).
|
|
508
|
+
* Policy actions: `read`, `write`, `delete`, `list`, `meta:read`, `meta:write`, `unquery`.
|
|
509
|
+
*
|
|
510
|
+
* @example Tenant isolation: first path segment must equal app-user attribute `tenant_code`.
|
|
511
|
+
* ```ts
|
|
512
|
+
* await client.createPolicy('tenant_isolation', {
|
|
513
|
+
* effect: 'allow',
|
|
514
|
+
* priority: 100,
|
|
515
|
+
* subjects: { type: 'app_user' },
|
|
516
|
+
* actions: ['read'],
|
|
517
|
+
* resources: { identifiers: [{ match_start: '/' }] },
|
|
518
|
+
* conditions: { expression: 'resource.path[0] = subject.attr.tenant_code' },
|
|
519
|
+
* });
|
|
520
|
+
* ```
|
|
521
|
+
*
|
|
522
|
+
* @example Deny viewers write access under `/admin/`.
|
|
523
|
+
* ```ts
|
|
524
|
+
* await client.createPolicy('deny_viewers_admin', {
|
|
525
|
+
* effect: 'deny',
|
|
526
|
+
* priority: 10,
|
|
527
|
+
* subjects: { type: 'app_user', groups: ['viewers'] },
|
|
528
|
+
* resources: { identifiers: [{ match_start: '/admin/' }] },
|
|
529
|
+
* actions: ['write', 'delete', 'meta:write'],
|
|
530
|
+
* });
|
|
531
|
+
* ```
|
|
532
|
+
*
|
|
533
|
+
* @example Branch-only rule via `conditions.branches`.
|
|
534
|
+
* ```ts
|
|
535
|
+
* await client.createPolicy('staging_only', {
|
|
536
|
+
* effect: 'allow',
|
|
537
|
+
* priority: 50,
|
|
538
|
+
* subjects: { type: 'app_user', groups: ['qa'] },
|
|
539
|
+
* actions: ['read', 'write'],
|
|
540
|
+
* resources: { identifiers: [{ match_start: '/staging/' }] },
|
|
541
|
+
* conditions: { branches: ['stg', 'stg*'] },
|
|
542
|
+
* });
|
|
543
|
+
* ```
|
|
544
|
+
*/
|
|
505
545
|
async createPolicy(policyId, policy) {
|
|
506
546
|
return this.request('POST', '/api/v1/security/policies', {
|
|
507
547
|
policy_id: policyId,
|
|
@@ -524,6 +564,44 @@ class XCiteDBClient {
|
|
|
524
564
|
await this.request('DELETE', `/api/v1/security/policies/${encodeURIComponent(policyId)}`);
|
|
525
565
|
}
|
|
526
566
|
// --- Triggers (developer admin/editor) ---
|
|
567
|
+
/**
|
|
568
|
+
* Create or update a trigger (`POST /api/v1/triggers`). Definitions live under `/_xcitedb/triggers`.
|
|
569
|
+
* After matching events, the server runs `action.unquery` over `action.query` and writes JSON to
|
|
570
|
+
* `action.meta_path` on `action.target_identifier` (use `"$trigger_identifier"` for the firing doc).
|
|
571
|
+
* Unquery can use `$trigger_identifier`, `$trigger_meta_path`, `$trigger_operation`, `$trigger_value`.
|
|
572
|
+
*
|
|
573
|
+
* @example On meta change under `/projects/`, append a snapshot entry to an index document.
|
|
574
|
+
* ```ts
|
|
575
|
+
* await client.upsertTrigger('project_meta_index', {
|
|
576
|
+
* event: 'meta_changed',
|
|
577
|
+
* match: {
|
|
578
|
+
* identifiers: [{ match_start: '/projects/' }],
|
|
579
|
+
* match_meta_path: 'status',
|
|
580
|
+
* },
|
|
581
|
+
* action: {
|
|
582
|
+
* query: { match: '$trigger_identifier' },
|
|
583
|
+
* unquery: { lastId: '$trigger_identifier', path: '$trigger_meta_path' },
|
|
584
|
+
* target_identifier: '/indexes/project_meta',
|
|
585
|
+
* meta_path: 'entries',
|
|
586
|
+
* mode: 'append',
|
|
587
|
+
* },
|
|
588
|
+
* });
|
|
589
|
+
* ```
|
|
590
|
+
*
|
|
591
|
+
* @example On document write, write a computed summary onto the same identifier's meta.
|
|
592
|
+
* ```ts
|
|
593
|
+
* await client.upsertTrigger('doc_written_summary', {
|
|
594
|
+
* event: 'document_written',
|
|
595
|
+
* match: { identifiers: [{ match_start: '/articles/' }] },
|
|
596
|
+
* action: {
|
|
597
|
+
* query: { match: '$trigger_identifier' },
|
|
598
|
+
* unquery: { id: '$identifier', nodeCount: '$count' },
|
|
599
|
+
* target_identifier: '$trigger_identifier',
|
|
600
|
+
* meta_path: 'stats',
|
|
601
|
+
* },
|
|
602
|
+
* });
|
|
603
|
+
* ```
|
|
604
|
+
*/
|
|
527
605
|
async upsertTrigger(triggerId, trigger) {
|
|
528
606
|
return this.request('POST', '/api/v1/triggers', {
|
|
529
607
|
trigger_id: triggerId,
|
|
@@ -544,6 +622,29 @@ class XCiteDBClient {
|
|
|
544
622
|
const q = buildQuery({ name });
|
|
545
623
|
await this.request('DELETE', `/api/v1/triggers${q}`);
|
|
546
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* Dry-run access check (`POST /api/v1/security/check`). Returns `effect` and optional `matched_policy_id`.
|
|
627
|
+
* Useful for debugging policies. Actions: `read`, `write`, `delete`, `list`, `meta:read`, `meta:write`, `unquery`.
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```ts
|
|
631
|
+
* const r = await client.checkAccess(
|
|
632
|
+
* {
|
|
633
|
+
* type: 'app_user',
|
|
634
|
+
* user_id: 'u1',
|
|
635
|
+
* email: 'alice@example.com',
|
|
636
|
+
* groups: ['editors'],
|
|
637
|
+
* role: 'app_user',
|
|
638
|
+
* attributes: { tenant_code: 'acme', level: 5 },
|
|
639
|
+
* },
|
|
640
|
+
* '/acme/reports/q1',
|
|
641
|
+
* 'read',
|
|
642
|
+
* undefined,
|
|
643
|
+
* 'main'
|
|
644
|
+
* );
|
|
645
|
+
* console.log(r.effect, r.matched_policy_id);
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
547
648
|
async checkAccess(subject, identifier, action, metaPath, branch) {
|
|
548
649
|
const body = { subject, identifier, action };
|
|
549
650
|
if (metaPath !== undefined)
|
|
@@ -555,6 +656,19 @@ class XCiteDBClient {
|
|
|
555
656
|
async getSecurityConfig() {
|
|
556
657
|
return this.request('GET', '/api/v1/security/config');
|
|
557
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Update tenant security defaults (`PUT /api/v1/security/config`). When ABAC is enabled, pair
|
|
661
|
+
* `app_user_default_effect: 'deny'` with explicit allow policies for least privilege.
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* await client.updateSecurityConfig({
|
|
666
|
+
* app_user_default_effect: 'deny',
|
|
667
|
+
* default_effect: 'allow',
|
|
668
|
+
* developer_bypass: true,
|
|
669
|
+
* });
|
|
670
|
+
* ```
|
|
671
|
+
*/
|
|
558
672
|
async updateSecurityConfig(config) {
|
|
559
673
|
await this.request('PUT', '/api/v1/security/config', config);
|
|
560
674
|
}
|
|
@@ -887,6 +1001,31 @@ class XCiteDBClient {
|
|
|
887
1001
|
async findLocks(identifier) {
|
|
888
1002
|
return this.request('GET', `/api/v1/locks${buildQuery({ identifier })}`);
|
|
889
1003
|
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Run Unquery (`POST /api/v1/unquery`): declarative analytics over documents matching `query`.
|
|
1006
|
+
* The `unquery` argument is a JSON template; keys are output fields, string values are expressions.
|
|
1007
|
+
*
|
|
1008
|
+
* @example Project a meta field into a result key.
|
|
1009
|
+
* ```ts
|
|
1010
|
+
* const out = await client.unquery<{ tag: string }>(
|
|
1011
|
+
* { match_start: '/manual/' },
|
|
1012
|
+
* { title: 'chapter_title' }
|
|
1013
|
+
* );
|
|
1014
|
+
* ```
|
|
1015
|
+
*
|
|
1016
|
+
* @example Count matching documents.
|
|
1017
|
+
* ```ts
|
|
1018
|
+
* const out = await client.unquery<{ total: number }>({ match_start: '/orders/' }, { total: '$count' });
|
|
1019
|
+
* ```
|
|
1020
|
+
*
|
|
1021
|
+
* @example XPath from XML (string value must escape quotes for TS).
|
|
1022
|
+
* ```ts
|
|
1023
|
+
* const out = await client.unquery<{ heading: string }>(
|
|
1024
|
+
* { match: '/book/ch1' },
|
|
1025
|
+
* { heading: '$xpath("//h1")' }
|
|
1026
|
+
* );
|
|
1027
|
+
* ```
|
|
1028
|
+
*/
|
|
890
1029
|
async unquery(query, unquery) {
|
|
891
1030
|
return this.request('POST', '/api/v1/unquery', { query, unquery });
|
|
892
1031
|
}
|
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, DatabaseContext, Flags, JsonDocumentData, IdentifierChildNode, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, OAuthProviderInfo, OAuthProvidersResponse, OwnedTenantInfo, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspaceOrg, PlatformWorkspacesResponse, LogEntry, MetaValue, PlatformRegisterResult, PolicyUpdateResponse, PolicyConditions, PolicyIdentifierPattern, PolicyResources, PolicySubjectInput, PolicySubjects, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredPolicyResponse, StoredTriggerResponse, SubscriptionOptions, TextSearchHit, TextSearchQuery, TextSearchResult, TriggerDefinition, TokenPair, UserInfo, WriteDocumentOptions, CreateTestSessionOptions, XCiteDBClientOptions, UnqueryResult, XCiteQuery, } from './types';
|
|
3
|
+
export type { AccessCheckResult, ApiKeyInfo, AppAuthConfig, AppEmailConfig, AppEmailSmtpConfig, AppEmailTemplateEntry, AppEmailTemplates, AppEmailWebhookConfig, AppUser, AppUserTokenPair, EmailTestResponse, ForgotPasswordResponse, SendVerificationResponse, DatabaseContext, Flags, JsonDocumentData, IdentifierChildNode, ListIdentifierChildrenResult, ListIdentifiersResult, LockInfo, OAuthProviderInfo, OAuthProvidersResponse, OwnedTenantInfo, ProjectInfo, PlatformRegistrationConfig, PlatformWorkspaceOrg, PlatformWorkspacesResponse, LogEntry, MetaValue, PlatformRegisterResult, PolicyUpdateResponse, PolicyConditions, PolicyIdentifierPattern, PolicyResources, PolicySubjectInput, PolicySubjects, RealtimeEvent, SecurityConfig, SecurityPolicy, StoredPolicyResponse, StoredTriggerResponse, SubscriptionOptions, TextSearchHit, TextSearchQuery, TextSearchResult, TriggerDefinition, TokenPair, UserInfo, WriteDocumentOptions, CreateTestSessionOptions, XCiteDBClientOptions, UnqueryResult, UnqueryTemplate, XCiteQuery, } from './types';
|
|
4
4
|
export { XCiteDBError } from './types';
|
package/dist/types.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export type JsonDocumentData = Record<string, unknown>;
|
|
|
20
20
|
export type MetaValue = unknown;
|
|
21
21
|
/** Result of `unquery` (shape depends on the unquery definition). */
|
|
22
22
|
export type UnqueryResult = unknown;
|
|
23
|
+
/**
|
|
24
|
+
* Unquery DSL template document. Object keys become output field names; string values are
|
|
25
|
+
* expressions (e.g. `"$count"`, `"$xpath(\"//title\")"`, or a meta field name). Supports nested
|
|
26
|
+
* objects, arrays, and `$`-prefixed builtins. See `llms-full.txt` shipped with this package for
|
|
27
|
+
* the full DSL reference.
|
|
28
|
+
*/
|
|
29
|
+
export type UnqueryTemplate = Record<string, unknown>;
|
|
23
30
|
/** Typical `POST /api/v1/platform/auth/register` response (fields vary by registration policy). */
|
|
24
31
|
export interface PlatformRegisterResult {
|
|
25
32
|
user_id?: string;
|
|
@@ -340,6 +347,12 @@ export interface PolicyResources {
|
|
|
340
347
|
}
|
|
341
348
|
export interface PolicyConditions {
|
|
342
349
|
branches?: string[];
|
|
350
|
+
/**
|
|
351
|
+
* Unquery condition expression.
|
|
352
|
+
* Policies: evaluated against `{ subject, resource, env }`.
|
|
353
|
+
* Triggers: evaluated against `{ trigger, value, resource, env }` (see server docs).
|
|
354
|
+
*/
|
|
355
|
+
expression?: string;
|
|
343
356
|
}
|
|
344
357
|
export interface SecurityPolicy {
|
|
345
358
|
description?: string;
|
|
@@ -358,6 +371,8 @@ export interface PolicySubjectInput {
|
|
|
358
371
|
groups?: string[];
|
|
359
372
|
role?: string;
|
|
360
373
|
username?: string;
|
|
374
|
+
/** Custom app-user attributes (mirrors stored user `attributes`); used by `conditions.expression`. */
|
|
375
|
+
attributes?: Record<string, unknown>;
|
|
361
376
|
}
|
|
362
377
|
export interface SecurityConfig {
|
|
363
378
|
default_effect: 'allow' | 'deny';
|
|
@@ -386,8 +401,29 @@ export interface PolicyUpdateResponse {
|
|
|
386
401
|
policy: SecurityPolicy;
|
|
387
402
|
warnings?: string[];
|
|
388
403
|
}
|
|
389
|
-
/**
|
|
390
|
-
export
|
|
404
|
+
/** `match` block for stored triggers (`/_xcitedb/triggers`). */
|
|
405
|
+
export interface TriggerMatch {
|
|
406
|
+
/** Non-empty array of identifier patterns (same shape as policy `resources.identifiers`). */
|
|
407
|
+
identifiers: PolicyIdentifierPattern[];
|
|
408
|
+
match_meta_path?: string;
|
|
409
|
+
match_operation?: 'set' | 'append' | 'delete';
|
|
410
|
+
}
|
|
411
|
+
/** `action` block: run unquery and write result to target meta. */
|
|
412
|
+
export interface TriggerAction {
|
|
413
|
+
query: XCiteQuery;
|
|
414
|
+
unquery: UnqueryTemplate;
|
|
415
|
+
target_identifier: string;
|
|
416
|
+
meta_path: string;
|
|
417
|
+
mode?: 'set' | 'append';
|
|
418
|
+
}
|
|
419
|
+
/** Stored trigger document under /_xcitedb/triggers. */
|
|
420
|
+
export interface TriggerDefinition {
|
|
421
|
+
enabled?: boolean;
|
|
422
|
+
event: 'meta_changed' | 'document_written' | 'document_deleted';
|
|
423
|
+
match: TriggerMatch;
|
|
424
|
+
conditions?: PolicyConditions;
|
|
425
|
+
action: TriggerAction;
|
|
426
|
+
}
|
|
391
427
|
export interface StoredTriggerResponse {
|
|
392
428
|
trigger_id: string;
|
|
393
429
|
trigger: TriggerDefinition;
|
package/llms-full.txt
CHANGED
|
@@ -435,6 +435,122 @@ Executes a structured query document (JSON DSL) for advanced analytics, bulk exp
|
|
|
435
435
|
|
|
436
436
|
Unquery supports: hierarchical navigation (self, parents, ancestors, children, descendants), XPath queries on XML, JSON path navigation, counts, sums, string operations, type casting, and conditional branching. Results are always structured JSON.
|
|
437
437
|
|
|
438
|
+
## Unquery DSL reference
|
|
439
|
+
|
|
440
|
+
The `unquery` body is a **JSON template**: each **object key** names an output field; each **value** is either a nested object/array (recursed) or a **string parsed as an expression**. Arrays produce JSON arrays in order.
|
|
441
|
+
|
|
442
|
+
### Core expression builtins (string values)
|
|
443
|
+
|
|
444
|
+
- **Document / path:** `$identifier`, `$identifier(n)` (path segment by index), `$key`, `$index`, `$path`
|
|
445
|
+
- **XML:** `$xpath("expr")`, `$lxpath("expr")` (leaf / no-children variant), `$xml`, `$xml_no_children`, `$node`, `$attr("name")`, `$child("name")`, `$text(expr)`
|
|
446
|
+
- **Aggregates / size:** `$count`, `$sum(expr)`, `$avg(expr)`, `$min(expr)`, `$max(expr)`, `$size(expr)` (array length), `$length(expr)` (string length)
|
|
447
|
+
- **String ops:** `$lower(expr)`, `$upper(expr)`, `$substr(s,start,len?)`, `$replace(src,from,to,all?)`, `$split(s,delim)`, `$join(arr,delim?)`, `$find`, `$ifind`
|
|
448
|
+
- **Time / casts:** `$now`, `$to_time(expr,fmt?)`, `$time_to_str(expr,fmt?)`, `$string`, `$number`, `$int`, `$float`, `$bool(expr)`
|
|
449
|
+
- **Control:** `$if(cond, then, else)`, `$var(name)` or `%name` (template variables), `$call(name)` (user `#func`), `$prev(default)`
|
|
450
|
+
- **Other:** `$node_date`, `$data_date(expr?)`, `$in_filter("name")`, `$file`, `$csv`, `$env`, `$filename` (last three blocked in safety mode for standalone `evaluateCondition`)
|
|
451
|
+
|
|
452
|
+
### Key-side syntax (JSON object member **names**, not values)
|
|
453
|
+
|
|
454
|
+
- Plain names, dotted paths, `[index]`, `$(expression)` / `$expr` for dynamic keys
|
|
455
|
+
- **`#if`**, **`#var`**, **`#assign`**, **`#func name (a,b,…)`**, **`#exists`**, **`#notexists`**, **`#return`**, **`#returnif`**
|
|
456
|
+
- Suffixes on keys: `?condition` (filter branch), `@ ascending` / `@ descending` / `@ unique_ascending` / `@ unique_descending` on values
|
|
457
|
+
- **Context navigation** after `->` (in key paths): `$self`, `$parent`, `$ancestors`, `$ancestors_and_self`, `$children`, `$descendants`, `$descendants_and_self`, `$date`, `$branch`, `$all`, `$var`, `$file`, `$csv`
|
|
458
|
+
|
|
459
|
+
### Conditions (same grammar as policy `conditions.expression` and Unquery `?` on keys)
|
|
460
|
+
|
|
461
|
+
Operators: `=`, `!=`, `<`, `>`, `<=`, `>=`, `in`, `not_in`, `contains`, `starts_with`, `ends_with`, `matches`, `is_array`, `is_object`, `is_string`, `is_number`, `is_int`, `is_float`, `is_bool`, `is_literal`. Logic: `&` (AND), `|` (OR), `!` (NOT). Postfix `!` on an expression tests **field exists**.
|
|
462
|
+
|
|
463
|
+
### Graded examples
|
|
464
|
+
|
|
465
|
+
**1. Project one meta field into an output key** (per matching document, then combined per engine rules):
|
|
466
|
+
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"query": { "match_start": "/manual/" },
|
|
470
|
+
"unquery": { "title": "chapter_title" }
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
**2. Count documents in a prefix:**
|
|
475
|
+
|
|
476
|
+
```json
|
|
477
|
+
{
|
|
478
|
+
"query": { "match_start": "/orders/" },
|
|
479
|
+
"unquery": { "total": "$count" }
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**3. XPath from XML:**
|
|
484
|
+
|
|
485
|
+
```json
|
|
486
|
+
{
|
|
487
|
+
"query": { "match": "/book/ch1" },
|
|
488
|
+
"unquery": { "heading": "$xpath(\"//h1\")" }
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**4. Nested object with conditional key** (illustrative; exact key syntax may use `#if` blocks for complex trees):
|
|
493
|
+
|
|
494
|
+
```json
|
|
495
|
+
{
|
|
496
|
+
"query": { "match_start": "/items/" },
|
|
497
|
+
"unquery": {
|
|
498
|
+
"id": "$identifier",
|
|
499
|
+
"summary": {
|
|
500
|
+
"len": "$length(title_field)"
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
SDK: `UnqueryTemplate` in `@xcitedbs/client` types; method `unquery(query, unquery)`.
|
|
507
|
+
|
|
508
|
+
## ABAC policy expression language
|
|
509
|
+
|
|
510
|
+
Policies may set **`conditions.expression`** (optional) and **`conditions.branches`** (optional array). If `branches` is non-empty, the request branch must match an entry (`"*"`, exact name, or `prefix*`).
|
|
511
|
+
|
|
512
|
+
### Evaluation context for **policies** (`conditions.expression`)
|
|
513
|
+
|
|
514
|
+
```json
|
|
515
|
+
{
|
|
516
|
+
"subject": {
|
|
517
|
+
"id": "...",
|
|
518
|
+
"email": "...",
|
|
519
|
+
"type": "app_user|developer|...",
|
|
520
|
+
"role": "...",
|
|
521
|
+
"groups": ["..."],
|
|
522
|
+
"attr": { }
|
|
523
|
+
},
|
|
524
|
+
"resource": {
|
|
525
|
+
"identifier": "/full/path",
|
|
526
|
+
"path": ["segment", "segment"]
|
|
527
|
+
},
|
|
528
|
+
"env": { "branch": "..." }
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
`subject.attr` mirrors app-user **custom attributes** from the user record. `resource.path` is the identifier split on `/` (non-empty segments only).
|
|
533
|
+
|
|
534
|
+
### Operators (predicates)
|
|
535
|
+
|
|
536
|
+
`=`, `!=`, `>=`, `<=`, `>`, `<`, `in`, `contains`, `starts_with`, `ends_with`, `&`, `|`, `!`, `+` (string concat), postfix `!` (exists).
|
|
537
|
+
|
|
538
|
+
### Policy action strings (in `actions` arrays)
|
|
539
|
+
|
|
540
|
+
Use: **`read`**, **`write`**, **`delete`**, **`list`**, **`meta:read`**, **`meta:write`**, **`unquery`**. (Do not use legacy `document:write`-style names in new policies.)
|
|
541
|
+
|
|
542
|
+
### Copy-pasteable expression recipes (from integration tests)
|
|
543
|
+
|
|
544
|
+
| Scenario | `conditions.expression` |
|
|
545
|
+
|----------|-------------------------|
|
|
546
|
+
| Tenant isolation (first path segment = user attr) | `resource.path[0] = subject.attr.tenant_code` |
|
|
547
|
+
| Numeric level | `subject.attr.level >= 5` |
|
|
548
|
+
| Project membership (second segment in array attr) | `resource.path[1] in subject.attr.projects` |
|
|
549
|
+
| Boolean feature flag | `subject.attr.beta = true` |
|
|
550
|
+
| Compound + branch (also use `conditions.branches` when needed) | `subject.email ends_with '@company.com' \| (subject.email ends_with '@partner.com' & env.branch = 'stg')` |
|
|
551
|
+
|
|
552
|
+
Dry-run: **`POST /api/v1/security/check`** with `subject`, `identifier`, `action`, optional `meta_path`, `branch`.
|
|
553
|
+
|
|
438
554
|
---
|
|
439
555
|
|
|
440
556
|
# Branches
|
|
@@ -569,27 +685,111 @@ Returns lock info. **`409`** if already locked.
|
|
|
569
685
|
|
|
570
686
|
**Base path:** `/api/v1/triggers`
|
|
571
687
|
|
|
688
|
+
Definitions are stored as JSON under **`/_xcitedb/triggers`**. After a matching event, the server runs **`action.unquery`** over documents selected by **`action.query`**, then writes the resulting JSON to **`action.meta_path`** on **`action.target_identifier`** (elevated privileges inside the same transaction). Nested trigger evaluation is blocked (no infinite loops).
|
|
689
|
+
|
|
572
690
|
## Create or update trigger
|
|
573
691
|
|
|
574
692
|
**`POST /api/v1/triggers`**
|
|
575
693
|
|
|
576
694
|
```json
|
|
577
695
|
{
|
|
578
|
-
"trigger_id": "
|
|
696
|
+
"trigger_id": "on_project_status_meta",
|
|
697
|
+
"trigger": {
|
|
698
|
+
"enabled": true,
|
|
699
|
+
"event": "meta_changed",
|
|
700
|
+
"match": {
|
|
701
|
+
"identifiers": [{ "match_start": "/projects/" }],
|
|
702
|
+
"match_meta_path": "status",
|
|
703
|
+
"match_operation": "set"
|
|
704
|
+
},
|
|
705
|
+
"conditions": {
|
|
706
|
+
"branches": ["*", "main"],
|
|
707
|
+
"expression": "trigger.meta_path = \"status\""
|
|
708
|
+
},
|
|
709
|
+
"action": {
|
|
710
|
+
"query": { "match": "$trigger_identifier" },
|
|
711
|
+
"unquery": { "id": "$identifier", "status": "status" },
|
|
712
|
+
"target_identifier": "/indexes/project_status",
|
|
713
|
+
"meta_path": "entries",
|
|
714
|
+
"mode": "append"
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
### Trigger fields
|
|
721
|
+
|
|
722
|
+
| Field | Required | Description |
|
|
723
|
+
|--------|----------|-------------|
|
|
724
|
+
| `enabled` | No (default true) | If false, trigger is skipped. |
|
|
725
|
+
| `event` | Yes | `meta_changed`, `document_written`, or `document_deleted`. |
|
|
726
|
+
| `match` | Yes | Must include **`identifiers`**: non-empty array of identifier patterns (`exact`, `match_start`, `match_end`, `contains`, `regex`). Optional **`match_meta_path`**: exact path or prefix ending with `*`. Optional **`match_operation`**: `set`, `append`, or `delete` (meta / delete ops). |
|
|
727
|
+
| `conditions` | No | Optional **`branches`** (same as policies) and **`expression`** (see below). |
|
|
728
|
+
| `action` | Yes | **`query`** (`XCiteQuery`), **`unquery`** (Unquery DSL template), **`target_identifier`** (literal or `"$trigger_identifier"`), **`meta_path`**, optional **`mode`**: `set` (default) or `append`. |
|
|
729
|
+
|
|
730
|
+
### Expression context for **triggers** (`conditions.expression`)
|
|
731
|
+
|
|
732
|
+
Not the same as policies: there is **no `subject`**. Context object:
|
|
733
|
+
|
|
734
|
+
- **`trigger`**: `{ "event", "meta_path", "operation" }` (`operation`: `set` / `append` / `delete`)
|
|
735
|
+
- **`value`**: JSON written at `meta_path` for `meta_changed`, or null
|
|
736
|
+
- **`resource`**: `{ "identifier", "path" }` for the firing identifier
|
|
737
|
+
- **`env`**: `{ "branch" }`
|
|
738
|
+
|
|
739
|
+
### Unquery variables injected for triggers
|
|
740
|
+
|
|
741
|
+
String template vars: **`$trigger_identifier`**, **`$trigger_meta_path`**, **`$trigger_operation`**. JSON var: **`$trigger_value`** (the written value when applicable).
|
|
742
|
+
|
|
743
|
+
### Recipes
|
|
744
|
+
|
|
745
|
+
**Meta change → append row to an index document**
|
|
746
|
+
|
|
747
|
+
```json
|
|
748
|
+
{
|
|
749
|
+
"trigger_id": "meta_index",
|
|
750
|
+
"trigger": {
|
|
751
|
+
"event": "meta_changed",
|
|
752
|
+
"match": {
|
|
753
|
+
"identifiers": [{ "match_start": "/docs/" }],
|
|
754
|
+
"match_meta_path": "reviewed"
|
|
755
|
+
},
|
|
756
|
+
"action": {
|
|
757
|
+
"query": { "match": "$trigger_identifier" },
|
|
758
|
+
"unquery": { "doc": "$trigger_identifier", "at": "$trigger_meta_path" },
|
|
759
|
+
"target_identifier": "/indexes/reviews",
|
|
760
|
+
"meta_path": "log",
|
|
761
|
+
"mode": "append"
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
**Document written → write stats meta on the same identifier**
|
|
768
|
+
|
|
769
|
+
```json
|
|
770
|
+
{
|
|
771
|
+
"trigger_id": "article_stats",
|
|
579
772
|
"trigger": {
|
|
580
|
-
"
|
|
581
|
-
"
|
|
773
|
+
"event": "document_written",
|
|
774
|
+
"match": { "identifiers": [{ "match_start": "/articles/" }] },
|
|
775
|
+
"action": {
|
|
776
|
+
"query": { "match": "$trigger_identifier" },
|
|
777
|
+
"unquery": { "id": "$identifier", "nodes": "$count" },
|
|
778
|
+
"target_identifier": "$trigger_identifier",
|
|
779
|
+
"meta_path": "stats",
|
|
780
|
+
"mode": "set"
|
|
781
|
+
}
|
|
582
782
|
}
|
|
583
783
|
}
|
|
584
784
|
```
|
|
585
785
|
|
|
586
786
|
## List triggers
|
|
587
787
|
|
|
588
|
-
**`GET /api/v1/triggers`** — Returns map of `{ trigger_id: trigger_definition }`.
|
|
788
|
+
**`GET /api/v1/triggers`** — Returns map of `{ trigger_id: trigger_definition }`. Optional **`?name=`** returns one trigger as `{ trigger_id, trigger }`.
|
|
589
789
|
|
|
590
790
|
## Delete trigger
|
|
591
791
|
|
|
592
|
-
**`DELETE /api/v1/triggers?name=
|
|
792
|
+
**`DELETE /api/v1/triggers?name=on_project_status_meta`**
|
|
593
793
|
|
|
594
794
|
---
|
|
595
795
|
|
|
@@ -609,7 +809,7 @@ Returns lock info. **`409`** if already locked.
|
|
|
609
809
|
"priority": 10,
|
|
610
810
|
"subjects": { "type": "app_user", "groups": ["viewers"] },
|
|
611
811
|
"resources": { "identifiers": [{ "match_start": "/admin/" }] },
|
|
612
|
-
"actions": ["
|
|
812
|
+
"actions": ["write", "delete", "meta:write"],
|
|
613
813
|
"conditions": {}
|
|
614
814
|
}
|
|
615
815
|
}
|
|
@@ -630,11 +830,11 @@ Returns lock info. **`409`** if already locked.
|
|
|
630
830
|
{
|
|
631
831
|
"subject": { "type": "app_user", "groups": ["editors"] },
|
|
632
832
|
"identifier": "/admin/config",
|
|
633
|
-
"action": "
|
|
833
|
+
"action": "write"
|
|
634
834
|
}
|
|
635
835
|
```
|
|
636
836
|
|
|
637
|
-
Returns `{ effect: "allow"|"deny", matched_policy_id? }`.
|
|
837
|
+
Returns `{ effect: "allow"|"deny", matched_policy_id?, expression_context? }`.
|
|
638
838
|
|
|
639
839
|
## Security config
|
|
640
840
|
|
package/llms.txt
CHANGED
|
@@ -206,6 +206,26 @@ interface XCiteDBClientOptions {
|
|
|
206
206
|
**Triggers:**
|
|
207
207
|
- `upsertTrigger(id, trigger)` / `listTriggers()` / `deleteTrigger(name)` — Automation triggers
|
|
208
208
|
|
|
209
|
+
### Advanced: policy expressions (ABAC)
|
|
210
|
+
|
|
211
|
+
- **Actions** (use in `policy.actions`): `read`, `write`, `delete`, `list`, `meta:read`, `meta:write`, `unquery`.
|
|
212
|
+
- **`conditions.expression`** uses the same predicate syntax as Unquery `?` filters. **Context:** `subject.id`, `subject.email`, `subject.role`, `subject.groups`, `subject.attr.*` (app-user JSON attributes), `resource.identifier`, `resource.path` (array of path segments), `env.branch`.
|
|
213
|
+
- **Operators:** `=`, `!=`, `>=`, `<=`, `>`, `<`, `in`, `contains`, `starts_with`, `ends_with`, `&`, `|`, `!`, `+` (string concat), postfix `!` (exists).
|
|
214
|
+
- **Examples:** `resource.path[0] = subject.attr.tenant_code` — tenant isolation; `subject.attr.level >= 5` — numeric attribute gate.
|
|
215
|
+
|
|
216
|
+
### Advanced: triggers (stored under `/_xcitedb/triggers`)
|
|
217
|
+
|
|
218
|
+
- **Events:** `meta_changed`, `document_written`, `document_deleted`.
|
|
219
|
+
- **`match`:** required non-empty **`identifiers`** (same pattern objects as policy `resources.identifiers`); optional **`match_meta_path`** (exact or `prefix*`); optional **`match_operation`:** `set` | `append` | `delete`.
|
|
220
|
+
- **`action`:** **`query`** (document query), **`unquery`** (Unquery template), **`target_identifier`** (or `"$trigger_identifier"`), **`meta_path`**, **`mode`:** `set` | `append`.
|
|
221
|
+
- **Unquery vars:** `$trigger_identifier`, `$trigger_meta_path`, `$trigger_operation`, `$trigger_value`. **Trigger `conditions.expression` context:** `trigger.{event,meta_path,operation}`, `value`, `resource`, `env.branch` (no `subject`).
|
|
222
|
+
|
|
223
|
+
### Advanced: Unquery DSL (`unquery(query, unqueryDoc)`)
|
|
224
|
+
|
|
225
|
+
- JSON **keys** = output fields; **string values** = expressions referencing meta/XML (e.g. field name `"title"` reads meta key `title`).
|
|
226
|
+
- **Common builtins:** `$count`, `$sum(expr)`, `$avg(expr)`, `$min(expr)`, `$max(expr)`, `$xpath("…")`, `$identifier`, `$size(expr)`, `$length(expr)`, `$if(cond, a, b)`, `$var(name)` / `%name`.
|
|
227
|
+
- **Example:** `{ "query": { "match_start": "/orders/" }, "unquery": { "n": "$count" } }` — count documents. Full grammar: **`llms-full.txt`** in this package.
|
|
228
|
+
|
|
209
229
|
**App Users (admin):**
|
|
210
230
|
- `listAppUsers()` / `createAppUser()` / `deleteAppUser()` — Manage end-user accounts
|
|
211
231
|
- `registerAppUser(email, password, displayName?, attributes?)` — Self-registration (groups assigned from server config)
|