@aopslab/domain-kit-docman 0.1.4

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.
Files changed (64) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +6 -0
  3. package/README.md +79 -0
  4. package/dist/config/config.d.ts +55 -0
  5. package/dist/config/config.js +176 -0
  6. package/dist/domain-services/index.d.ts +7 -0
  7. package/dist/domain-services/index.js +7 -0
  8. package/dist/domain-services/jwt.d.ts +1 -0
  9. package/dist/domain-services/jwt.js +5 -0
  10. package/dist/domain-services/metrics.d.ts +5 -0
  11. package/dist/domain-services/metrics.js +7 -0
  12. package/dist/domain-services/presets.d.ts +3 -0
  13. package/dist/domain-services/presets.js +4 -0
  14. package/dist/domain-services/provider.d.ts +2 -0
  15. package/dist/domain-services/provider.js +564 -0
  16. package/dist/domain-services/resilience.d.ts +6 -0
  17. package/dist/domain-services/resilience.js +19 -0
  18. package/dist/domain-services/types.d.ts +179 -0
  19. package/dist/domain-services/types.js +1 -0
  20. package/dist/domain-services/unified.d.ts +272 -0
  21. package/dist/domain-services/unified.js +210 -0
  22. package/dist/errors/error.map.d.ts +21 -0
  23. package/dist/errors/error.map.js +47 -0
  24. package/dist/errors/friendly.d.ts +31 -0
  25. package/dist/errors/friendly.js +407 -0
  26. package/dist/errors/i18n.d.ts +4 -0
  27. package/dist/errors/i18n.js +10 -0
  28. package/dist/errors/index.d.ts +3 -0
  29. package/dist/errors/index.js +3 -0
  30. package/dist/index.d.ts +9 -0
  31. package/dist/index.js +7 -0
  32. package/dist/operations/catalog.d.ts +11 -0
  33. package/dist/operations/catalog.js +299 -0
  34. package/dist/operations/contract.d.ts +31 -0
  35. package/dist/operations/contract.js +667 -0
  36. package/dist/operations/dcm.d.ts +58 -0
  37. package/dist/operations/dcm.js +168 -0
  38. package/dist/operations/definition.d.ts +6 -0
  39. package/dist/operations/definition.js +140 -0
  40. package/dist/operations/executor.d.ts +10 -0
  41. package/dist/operations/executor.js +269 -0
  42. package/dist/operations/host-projection.d.ts +11 -0
  43. package/dist/operations/host-projection.js +156 -0
  44. package/dist/operations/index.d.ts +10 -0
  45. package/dist/operations/index.js +10 -0
  46. package/dist/operations/io-types.d.ts +125 -0
  47. package/dist/operations/io-types.js +1 -0
  48. package/dist/operations/schemas.d.ts +10 -0
  49. package/dist/operations/schemas.js +872 -0
  50. package/dist/operations/scope-owned-create.d.ts +3 -0
  51. package/dist/operations/scope-owned-create.js +12 -0
  52. package/dist/operations/tool-input.d.ts +11 -0
  53. package/dist/operations/tool-input.js +357 -0
  54. package/dist/operations/types.d.ts +37 -0
  55. package/dist/operations/types.js +1 -0
  56. package/dist/resources/index.d.ts +1 -0
  57. package/dist/resources/index.js +1 -0
  58. package/dist/resources/resources.docman.server.errors.d.ts +14 -0
  59. package/dist/resources/resources.docman.server.errors.js +36 -0
  60. package/dist/shared/index.d.ts +5 -0
  61. package/dist/shared/index.js +1 -0
  62. package/dist/shared/tool-input-guard.d.ts +1 -0
  63. package/dist/shared/tool-input-guard.js +1 -0
  64. package/package.json +69 -0
@@ -0,0 +1,667 @@
1
+ import { listDocmanOperationSpecs } from './catalog.js';
2
+ const SUMMARY_OVERRIDES = {
3
+ 'document.compose.index': 'Build composed document index for a document version.',
4
+ 'document.index.build': 'Build persisted retrieval index rows for a document version.',
5
+ 'document.index.get': 'Read persisted retrieval index snapshot for a document version.',
6
+ 'document.summary.build': 'Build persisted document and section/page summaries for a document version.',
7
+ 'document.summary.get': 'Read persisted document and section/page summaries for a document version.',
8
+ 'document.search': 'Search persisted retrieval index rows for a document version.',
9
+ 'document.scope.search': 'Search persisted retrieval index rows across latest document versions in one scope.',
10
+ 'document.answer-pack': 'Read a deterministic answer pack with citations for a document version.',
11
+ 'document.compose.fetch': 'Fetch composed source fragment with resolved asset references.',
12
+ 'document.publish.materialize': 'Materialize publish-ready fragment into markdown or html output.',
13
+ 'document.delete.safe': 'Safely delete a document graph with orphan protection.',
14
+ 'document-version.delete.safe': 'Safely delete one document version with orphan protection.',
15
+ 'document-version.import-headings': 'Import a parsed markdown heading graph into a document version.',
16
+ 'document-section-link.usage.list': 'List document usage for a section.',
17
+ };
18
+ const DOCS_OVERRIDES = {
19
+ 'document.compose.index': {
20
+ notes: [
21
+ 'route path /document-versions/:id/compose-index resolves documentVersionId from :id',
22
+ 'for direct domain API calls, compose bodies are plain payloads (no data wrapper)',
23
+ 'for agent invoke local-route calls, send pathParams.id for routes with :id',
24
+ ],
25
+ antiPatterns: [
26
+ 'sending compose payload as { "data": { ... } } in /api/docman calls',
27
+ ],
28
+ preconditions: ['documentVersionId must exist'],
29
+ postconditions: ['returns deterministic section/page index snapshot for the version'],
30
+ },
31
+ 'document.compose.fetch': {
32
+ notes: [
33
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
34
+ 'route path /document-versions/:id/compose-fetch injects documentVersionId from :id',
35
+ 'for agent invoke local-route calls, send pathParams.id; body.documentVersionId is optional on :id routes',
36
+ 'result returns resolved source text, effective compose format, and referenced asset metadata',
37
+ 'asset references are logical only: use asset://<assetUid-or-slug> or asset://<assetUid-or-slug>@<version>',
38
+ 'compose fetch does not expose raw asset ids, sourcePath values, or storageKey values inside returned source content',
39
+ ],
40
+ antiPatterns: ['sending compose fetch payload as { "input": { ... } }'],
41
+ preconditions: ['documentVersionId must exist'],
42
+ postconditions: ['returns resolved source fragment with kind, format, and asset metadata'],
43
+ },
44
+ 'document.index.build': {
45
+ notes: [
46
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
47
+ 'route path /document-versions/:id/index injects documentVersionId from :id on host calls',
48
+ 'build deletes and rebuilds the persisted structural index for the selected version+locale tuple',
49
+ 'index rows are deterministic and derived from the same composed document traversal used by compose fetch/index',
50
+ ],
51
+ antiPatterns: [
52
+ 'sending index build payload as { "input": { ... } }',
53
+ 'treating persisted index rows as an editable source of truth',
54
+ ],
55
+ preconditions: ['documentVersionId must exist'],
56
+ postconditions: ['returns persisted section/page retrieval snapshot with stable anchors and page ranges'],
57
+ },
58
+ 'document.index.get': {
59
+ notes: [
60
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
61
+ 'route path /document-versions/:id/index resolves documentVersionId from :id on host calls',
62
+ 'get does not rebuild missing rows; build is explicit in this phase',
63
+ ],
64
+ antiPatterns: [
65
+ 'sending index get payload as { "input": { ... } }',
66
+ 'assuming get implicitly composes or rebuilds rows',
67
+ ],
68
+ preconditions: ['documentVersionId must exist'],
69
+ postconditions: ['returns the last persisted retrieval snapshot for the selected locale tuple'],
70
+ },
71
+ 'document.summary.build': {
72
+ notes: [
73
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
74
+ 'route path /document-versions/:id/summaries injects documentVersionId from :id on host calls',
75
+ 'build explicitly refreshes the persisted index first, then derives deterministic document/section/page summaries for the same locale tuple',
76
+ 'document summary prefers authored document-version/document summary text when present; section and page summaries stay deterministic and extractive in this sprint slice',
77
+ ],
78
+ antiPatterns: [
79
+ 'sending summary build payload as { "input": { ... } }',
80
+ 'treating persisted summary rows as hand-edited authored content',
81
+ ],
82
+ preconditions: ['documentVersionId must exist'],
83
+ postconditions: ['returns persisted document/section/page summaries with source and summary token counts'],
84
+ },
85
+ 'document.summary.get': {
86
+ notes: [
87
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
88
+ 'route path /document-versions/:id/summaries resolves documentVersionId from :id on host calls',
89
+ 'get does not rebuild missing summaries; summary build is explicit in this phase',
90
+ ],
91
+ antiPatterns: [
92
+ 'sending summary get payload as { "input": { ... } }',
93
+ 'assuming get implicitly rebuilds the persisted index or summary rows',
94
+ ],
95
+ preconditions: ['documentVersionId must exist'],
96
+ postconditions: ['returns the last persisted summary snapshot for the selected locale tuple'],
97
+ },
98
+ 'document.search': {
99
+ notes: [
100
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
101
+ 'route path /document-versions/:id/search resolves documentVersionId from :id on host calls',
102
+ 'search stays db-agnostic: lexical, hybrid, and semantic ranking all run on persisted retrieval rows instead of vendor-specific DB FTS/vector features',
103
+ 'set retrievalStrategy to lexical, hybrid, or semantic depending on how much vector reranking you want',
104
+ 'search expects document.index.build to have populated rows for the same locale tuple first',
105
+ ],
106
+ antiPatterns: [
107
+ 'sending search payload as { "input": { ... } }',
108
+ 'expecting search to auto-build missing retrieval rows',
109
+ ],
110
+ preconditions: ['documentVersionId must exist', 'q must be non-empty'],
111
+ postconditions: ['returns compact section/page hits with anchors, breadcrumbs, scores, and excerpts'],
112
+ },
113
+ 'document.scope.search': {
114
+ notes: [
115
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
116
+ 'route path /scopes/:id/documents/search resolves scopeId from :id on host calls',
117
+ 'scope-wide search lists documents inside the scope and searches only the latest/current document version for each document',
118
+ 'scope-wide search auto-builds missing retrieval rows before searching each latest version',
119
+ 'result stays global-ranked and returns document-level provenance for every hit',
120
+ ],
121
+ antiPatterns: [
122
+ 'sending scope search payload as { "input": { ... } }',
123
+ 'expecting scope-wide search to include every historical document version',
124
+ ],
125
+ preconditions: ['scopeId must exist', 'q must be non-empty'],
126
+ postconditions: ['returns globally ranked section/page hits plus document provenance, aggregate counts, and build failure metadata'],
127
+ },
128
+ 'document.answer-pack': {
129
+ notes: [
130
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
131
+ 'route path /document-versions/:id/answer-pack resolves documentVersionId from :id on host calls',
132
+ 'answer-pack stays citation-first: it selects compact deterministic answer text from persisted document/section/page rows',
133
+ 'set retrievalStrategy to lexical, hybrid, or semantic depending on how much vector reranking you want',
134
+ 'answer-pack expects document.index.build or document.summary.build to have populated rows for the same locale tuple first',
135
+ 'result includes answer text, answerSource, citations, and provenance so agents can cite anchor/page evidence without re-reading full markdown',
136
+ ],
137
+ antiPatterns: [
138
+ 'sending answer-pack payload as { "input": { ... } }',
139
+ 'assuming answer-pack implicitly rebuilds missing index or summary rows',
140
+ ],
141
+ preconditions: ['documentVersionId must exist', 'q must be non-empty'],
142
+ postconditions: ['returns compact answer text plus citable anchors, excerpts, matchedBy fields, and provenance metadata'],
143
+ },
144
+ 'document.publish.materialize': {
145
+ notes: [
146
+ 'operation accepts one flat payload object; legacy input envelopes are intentionally unsupported',
147
+ 'route path /document-versions/:id/materialize injects documentVersionId from :id',
148
+ 'for agent invoke local-route calls, send pathParams.id; body.documentVersionId is optional on :id routes',
149
+ 'target must be markdown or html',
150
+ 'markdown target preserves composed source text as-is',
151
+ 'html target omits MDX import/export preambles and returns deterministic inline HTML content',
152
+ 'materialize target dispatch is registry-backed internally so future artifact exporters can plug in without widening this generic invoke contract yet',
153
+ 'result payload stays JSON-friendly and returns text content, mediaType, warnings, and referenced assets',
154
+ ],
155
+ antiPatterns: [
156
+ 'sending materialize payload as { "input": { ... } }',
157
+ 'expecting a binary stream or download attachment from the generic invoke path',
158
+ ],
159
+ preconditions: ['documentVersionId must exist', 'target must be markdown or html'],
160
+ postconditions: ['returns mediaType, content, warnings, and asset metadata for the selected fragment'],
161
+ },
162
+ 'document.delete.safe': {
163
+ notes: [
164
+ 'safe delete requires exact document title confirmation',
165
+ 'for agent invoke local-route calls, provide pathParams.id and body.confirmName',
166
+ ],
167
+ antiPatterns: ['calling safe delete without confirmName'],
168
+ preconditions: ['id and confirmName are required'],
169
+ postconditions: ['deletes orphan graph only and reports preserved shared nodes'],
170
+ },
171
+ 'document-version.delete.safe': {
172
+ notes: ['for agent invoke local-route calls, provide pathParams.id'],
173
+ preconditions: ['id is required'],
174
+ postconditions: ['deletes only target document version and reports preserved shared nodes'],
175
+ },
176
+ 'document-version.import-headings': {
177
+ notes: [
178
+ 'operation accepts one flat payload object with parsedGraph; markdown parsing belongs to CLI/tooling, not dm',
179
+ 'route path /document-versions/:id/import-headings resolves documentVersionId from :id on host calls',
180
+ 'for agent invoke local-route calls, send pathParams.id; body.documentVersionId is optional on :id routes',
181
+ 'default existingGraphPolicy is error; append and replace must be explicit',
182
+ 'H1 is ignored by the parser contract, H2/H3 are section nodes, and H4+ headings become page nodes',
183
+ 'direct body under H2/H3 section nodes is ignored in the MVP and returned as a warning',
184
+ 'set options.synthesizeOverviewPages=true to import direct H2/H3 body as child Overview pages',
185
+ 'doc mirror push remains a flat whole-document mirror migration path and is not changed by this operation',
186
+ ],
187
+ antiPatterns: [
188
+ 'sending raw markdown source directly to this dm operation',
189
+ 'using heading import as an implicit replace for an existing document graph',
190
+ ],
191
+ preconditions: ['documentVersionId must exist', 'scopeId must resolve from host context or input', 'parsedGraph.nodes is required'],
192
+ postconditions: ['creates section/page/document-section-link graph rows and section-page-link memberships for imported page nodes'],
193
+ },
194
+ 'document-version.create': {
195
+ notes: ['version numbers are unique within one documentId'],
196
+ antiPatterns: ['trying to create the same version number twice for one document'],
197
+ preconditions: ['documentId must exist', 'version must be unique per documentId'],
198
+ postconditions: ['creates exactly one new version row for the target document'],
199
+ },
200
+ 'page-version.create': {
201
+ notes: [
202
+ 'page-version owns source format; page remains format-agnostic identity metadata',
203
+ 'accepted source formats are md and mdx',
204
+ 'native compose/fetch accepts md and mdx page-version content only',
205
+ 'asset references inside md/mdx source should use asset://<assetUid-or-slug> or asset://<assetUid-or-slug>@<version>',
206
+ 'raw asset ids and filesystem-style asset paths are intentionally unsupported in page source',
207
+ ],
208
+ antiPatterns: [
209
+ 'assuming unsupported source types can still be stored as page-version.format values',
210
+ ],
211
+ preconditions: ['pageId must exist', 'version must be unique per pageId'],
212
+ postconditions: ['creates exactly one new page-version row for the target page'],
213
+ },
214
+ 'asset.create': {
215
+ notes: [
216
+ 'asset is the durable logical owner for publish-grade resources such as images and attached files',
217
+ 'placement concerns stay outside asset identity and should continue through embed/page-embed-link style records',
218
+ ],
219
+ preconditions: ['assetUid must be unique per tenant'],
220
+ postconditions: ['creates exactly one logical asset owner row'],
221
+ },
222
+ 'asset-version.create': {
223
+ notes: [
224
+ 'asset-version stores content-addressed source/publication metadata for one immutable resource revision',
225
+ 'mutable follow-up updates should stay limited to lifecycle metadata such as status, label, variants, or meta',
226
+ 'compose-time asset resolution expects a publication locator on sourceUrl when source content references this version',
227
+ ],
228
+ antiPatterns: [
229
+ 'using asset-version as the only page placement record',
230
+ 'patching storage locator or content hash instead of creating a new version',
231
+ ],
232
+ preconditions: ['assetId must exist', 'version must be unique per assetId'],
233
+ postconditions: ['creates exactly one version row for the target asset'],
234
+ },
235
+ 'asset-version.update': {
236
+ notes: [
237
+ 'asset-version update is intended for lifecycle metadata only',
238
+ ],
239
+ antiPatterns: [
240
+ 'treating update as a substitute for creating a new content revision',
241
+ ],
242
+ preconditions: ['id is required', 'patch should only contain lifecycle metadata fields'],
243
+ postconditions: ['updates lifecycle metadata without changing asset identity'],
244
+ },
245
+ 'section-page-link.create': {
246
+ notes: [
247
+ 'section-page links are flat; pages live directly under a section',
248
+ 'position must be unique within the same sectionId',
249
+ ],
250
+ antiPatterns: [
251
+ 'trying to attach one page under another page',
252
+ 'reusing the same position inside one sectionId',
253
+ ],
254
+ preconditions: [
255
+ 'position must be unique per sectionId',
256
+ 'sectionId must reference an existing section',
257
+ ],
258
+ postconditions: ['render order is deterministic by sectionId + position'],
259
+ },
260
+ 'document-section-link.create': {
261
+ notes: [
262
+ 'document trees can nest sections under sections',
263
+ 'pages are content nodes and may attach at document root or under a section container',
264
+ ],
265
+ antiPatterns: [
266
+ 'trying to attach one page under another page',
267
+ 'trying to nest a section under a page',
268
+ ],
269
+ preconditions: [
270
+ 'when parentLinkId is set, it must reference a section link',
271
+ ],
272
+ postconditions: ['document tree stays root-or-section -> page and section -> section/page shaped'],
273
+ },
274
+ };
275
+ const CREATE_DATA_EXAMPLES = {
276
+ 'document-group.create': { groupUid: 'GRP-EXAMPLE-001', title: 'Guides' },
277
+ 'document.create': {
278
+ documentUid: 'DOC-EXAMPLE-001',
279
+ title: 'Sample document',
280
+ summary: 'Sample summary',
281
+ status: 'draft',
282
+ visibility: 'internal',
283
+ },
284
+ 'document-version.create': {
285
+ documentId: '<documentId>',
286
+ version: 1,
287
+ status: 'draft',
288
+ title: 'Sample document v1',
289
+ },
290
+ 'section.create': { sectionUid: 'SEC-EXAMPLE-001', title: 'Introduction', kind: 'container' },
291
+ 'page.create': { pageUid: 'PAG-EXAMPLE-001', title: 'Sample page', kind: 'content' },
292
+ 'page-version.create': {
293
+ pageId: '<pageId>',
294
+ version: 1,
295
+ status: 'draft',
296
+ title: 'Sample page',
297
+ format: 'md',
298
+ content: '# Sample page\n\nBody.',
299
+ },
300
+ 'document-section-link.create': {
301
+ documentVersionId: '<documentVersionId>',
302
+ kind: 'section',
303
+ sectionId: '<sectionId>',
304
+ position: 1,
305
+ },
306
+ 'section-page-link.create': {
307
+ sectionId: '<sectionId>',
308
+ pageVersionId: '<pageVersionId>',
309
+ position: 1,
310
+ },
311
+ 'snippet.create': {
312
+ snippetUid: 'SNP-EXAMPLE-001',
313
+ language: 'ts',
314
+ title: 'Hello snippet',
315
+ code: 'console.log("hello")',
316
+ },
317
+ 'page-snippet-link.create': {
318
+ pageVersionId: '<pageVersionId>',
319
+ snippetId: '<snippetId>',
320
+ position: 1,
321
+ },
322
+ 'asset.create': {
323
+ assetUid: 'AST-EXAMPLE-001',
324
+ kind: 'image',
325
+ title: 'Architecture diagram',
326
+ altText: 'System architecture overview',
327
+ },
328
+ 'asset-version.create': {
329
+ assetId: '<assetId>',
330
+ version: 1,
331
+ status: 'ready',
332
+ filename: 'architecture.png',
333
+ mime: 'image/png',
334
+ contentHash: 'sha256:<hash>',
335
+ sourceUrl: 'https://cdn.example.test/assets/architecture.v1.png',
336
+ },
337
+ 'embed.create': {
338
+ embedUid: 'EMB-EXAMPLE-001',
339
+ type: 'image',
340
+ title: 'Architecture',
341
+ url: 'https://example.com/architecture.png',
342
+ },
343
+ 'page-embed-link.create': {
344
+ pageVersionId: '<pageVersionId>',
345
+ embedId: '<embedId>',
346
+ position: 1,
347
+ },
348
+ };
349
+ const UPDATE_PATCH_EXAMPLES = {
350
+ 'document-group.update': { title: 'Updated group title' },
351
+ 'document.update': { title: 'Updated document title', summary: 'Updated summary' },
352
+ 'document-version.update': { title: 'Updated version title', status: 'draft' },
353
+ 'section.update': { title: 'Updated section title' },
354
+ 'page.update': { title: 'Updated page title' },
355
+ 'page-version.update': { title: 'Updated page version title' },
356
+ 'asset.update': { title: 'Updated asset title', altText: 'Updated alt text' },
357
+ 'asset-version.update': { status: 'ready', label: 'published' },
358
+ };
359
+ const LIST_FILTER_EXAMPLES = {
360
+ 'document.list': { status: 'draft' },
361
+ 'document-version.list': { documentId: '<documentId>' },
362
+ 'document-section-link.list': { documentVersionId: '<documentVersionId>' },
363
+ 'section-page-link.list': { sectionId: '<sectionId>' },
364
+ 'page-version.list': { pageId: '<pageId>' },
365
+ 'asset-version.list': { assetId: '<assetId>', status: 'ready' },
366
+ };
367
+ const LIST_OPTIONS_EXAMPLES = {
368
+ 'document.list': { includeVersionInfo: true },
369
+ };
370
+ const EXAMPLE_OVERRIDES = {
371
+ 'document.delete.safe': [{ id: '<documentId>', confirmName: '<documentTitle>' }],
372
+ 'document-version.delete.safe': [{ id: '<documentVersionId>' }],
373
+ 'document-version.import-headings': [
374
+ {
375
+ documentVersionId: '<documentVersionId>',
376
+ parsedGraph: {
377
+ sourceHash: '<sha256>',
378
+ sourcePath: 'docs/ui-system-v2.md',
379
+ nodes: [
380
+ {
381
+ kind: 'section',
382
+ title: 'Navigation',
383
+ children: [
384
+ {
385
+ kind: 'page',
386
+ title: 'Behavior',
387
+ bodyMarkdown: 'Page body.',
388
+ },
389
+ ],
390
+ },
391
+ ],
392
+ },
393
+ options: {
394
+ dryRun: true,
395
+ existingGraphPolicy: 'error',
396
+ slugStrategy: 'hash-suffix-on-collision',
397
+ bodyAssignment: 'leaf-page-content',
398
+ headingToPagePolicy: 'h4-and-below',
399
+ synthesizeOverviewPages: true,
400
+ },
401
+ },
402
+ ],
403
+ 'document.compose.index': [
404
+ {
405
+ documentVersionId: '<documentVersionId>',
406
+ options: { locale: 'en', fallbackLocale: 'tr' },
407
+ },
408
+ ],
409
+ 'document.compose.fetch': [
410
+ {
411
+ documentVersionId: '<documentVersionId>',
412
+ pageNumber: 1,
413
+ locale: 'en',
414
+ fallbackLocale: 'tr',
415
+ },
416
+ ],
417
+ 'document.summary.build': [
418
+ {
419
+ documentVersionId: '<documentVersionId>',
420
+ locale: 'en',
421
+ fallbackLocale: 'tr',
422
+ },
423
+ ],
424
+ 'document.summary.get': [
425
+ {
426
+ documentVersionId: '<documentVersionId>',
427
+ locale: 'en',
428
+ fallbackLocale: 'tr',
429
+ },
430
+ ],
431
+ 'document.answer-pack': [
432
+ {
433
+ documentVersionId: '<documentVersionId>',
434
+ q: 'regulator startup',
435
+ limit: 3,
436
+ locale: 'en',
437
+ fallbackLocale: 'tr',
438
+ },
439
+ ],
440
+ 'document.scope.search': [
441
+ {
442
+ scopeId: '<scopeId>',
443
+ q: 'regulator startup',
444
+ limit: 8,
445
+ retrievalStrategy: 'hybrid',
446
+ locale: 'en',
447
+ fallbackLocale: 'tr',
448
+ },
449
+ ],
450
+ 'document.publish.materialize': [
451
+ {
452
+ documentVersionId: '<documentVersionId>',
453
+ target: 'html',
454
+ locale: 'en',
455
+ fallbackLocale: 'tr',
456
+ },
457
+ ],
458
+ 'document-section-link.create': [
459
+ {
460
+ data: {
461
+ documentVersionId: '<documentVersionId>',
462
+ kind: 'page',
463
+ pageVersionId: '<rootPageVersionId>',
464
+ position: 1,
465
+ },
466
+ },
467
+ {
468
+ data: {
469
+ documentVersionId: '<documentVersionId>',
470
+ kind: 'section',
471
+ sectionId: '<sectionId>',
472
+ position: 2,
473
+ },
474
+ },
475
+ {
476
+ data: {
477
+ documentVersionId: '<documentVersionId>',
478
+ kind: 'page',
479
+ pageVersionId: '<sectionPageVersionId>',
480
+ parentLinkId: '<sectionLinkId>',
481
+ position: 1,
482
+ },
483
+ },
484
+ ],
485
+ 'document-section-link.usage.list': [{ sectionId: '<sectionId>' }],
486
+ 'section-page-link.create': [
487
+ {
488
+ data: {
489
+ sectionId: '<sectionId>',
490
+ pageVersionId: '<rootPageVersionId>',
491
+ position: 1,
492
+ },
493
+ },
494
+ {
495
+ data: {
496
+ sectionId: '<sectionId>',
497
+ pageVersionId: '<siblingPageVersionId>',
498
+ position: 2,
499
+ },
500
+ },
501
+ ],
502
+ };
503
+ function normalizeStringList(values) {
504
+ if (!values || values.length === 0)
505
+ return undefined;
506
+ const unique = new Set();
507
+ for (const value of values) {
508
+ const normalized = String(value ?? '').trim();
509
+ if (!normalized)
510
+ continue;
511
+ unique.add(normalized);
512
+ }
513
+ if (unique.size === 0)
514
+ return undefined;
515
+ return [...unique];
516
+ }
517
+ function mergeStringLists(...lists) {
518
+ const unique = new Set();
519
+ for (const list of lists) {
520
+ for (const item of list ?? []) {
521
+ const normalized = String(item ?? '').trim();
522
+ if (!normalized)
523
+ continue;
524
+ unique.add(normalized);
525
+ }
526
+ }
527
+ if (unique.size === 0)
528
+ return undefined;
529
+ return [...unique];
530
+ }
531
+ function toSummary(operationId) {
532
+ const override = SUMMARY_OVERRIDES[operationId];
533
+ if (override)
534
+ return override;
535
+ const normalized = operationId
536
+ .split('.')
537
+ .flatMap((segment) => segment.split('-'))
538
+ .join(' ')
539
+ .trim();
540
+ if (!normalized)
541
+ return operationId;
542
+ return normalized.charAt(0).toUpperCase() + normalized.slice(1);
543
+ }
544
+ function toSideEffect(kind) {
545
+ if (kind === 'list' || kind === 'get')
546
+ return 'none';
547
+ if (kind === 'custom')
548
+ return 'mixed';
549
+ return 'db';
550
+ }
551
+ function isDestructiveOperation(spec) {
552
+ return spec.kind === 'delete' || spec.operationId.includes('.delete.');
553
+ }
554
+ function toDefaultPolicy(spec) {
555
+ const destructive = isDestructiveOperation(spec);
556
+ const writeKind = spec.kind === 'create' || spec.kind === 'update' || spec.kind === 'delete';
557
+ const policy = {
558
+ scope: 'tenant',
559
+ auth: { required: true },
560
+ };
561
+ if (destructive || writeKind) {
562
+ policy.safety = {
563
+ destructive,
564
+ applyRequired: true,
565
+ confirmationRequired: spec.operationId.endsWith('.delete.safe'),
566
+ };
567
+ policy.rateLimit = {
568
+ bucket: destructive ? 'docman-write-destructive' : 'docman-write',
569
+ max: destructive ? 30 : 60,
570
+ windowSeconds: 60,
571
+ };
572
+ return policy;
573
+ }
574
+ policy.rateLimit = {
575
+ bucket: 'docman-read',
576
+ max: spec.kind === 'list' ? 180 : 240,
577
+ windowSeconds: 60,
578
+ };
579
+ return policy;
580
+ }
581
+ function toJsonExample(input) {
582
+ return JSON.stringify(input);
583
+ }
584
+ function toDefaultExampleFromArgs(spec) {
585
+ const payload = {};
586
+ for (const arg of spec.args) {
587
+ if (arg.name === 'id') {
588
+ payload.id = '<id>';
589
+ continue;
590
+ }
591
+ if (arg.name === 'data') {
592
+ payload.data = CREATE_DATA_EXAMPLES[spec.operationId] ?? { key: '<value>' };
593
+ continue;
594
+ }
595
+ if (arg.name === 'patch') {
596
+ payload.patch = UPDATE_PATCH_EXAMPLES[spec.operationId] ?? { key: '<value>' };
597
+ continue;
598
+ }
599
+ if (arg.name === 'filter') {
600
+ payload.filter = LIST_FILTER_EXAMPLES[spec.operationId] ?? {};
601
+ continue;
602
+ }
603
+ if (arg.name === 'options') {
604
+ payload.options = LIST_OPTIONS_EXAMPLES[spec.operationId] ?? {};
605
+ continue;
606
+ }
607
+ payload[arg.name] = `<${arg.name}>`;
608
+ }
609
+ if (Object.keys(payload).length === 0)
610
+ payload.input = '<payload>';
611
+ return toJsonExample(payload);
612
+ }
613
+ function toDefaultExamples(spec) {
614
+ const override = EXAMPLE_OVERRIDES[spec.operationId];
615
+ if (override && override.length > 0)
616
+ return override.map((entry) => toJsonExample(entry));
617
+ return [toDefaultExampleFromArgs(spec)];
618
+ }
619
+ function toNormalizedDocs(defaults, fromSpec) {
620
+ const notes = mergeStringLists(defaults?.notes, normalizeStringList(fromSpec?.notes));
621
+ const antiPatterns = mergeStringLists(defaults?.antiPatterns, normalizeStringList(fromSpec?.antiPatterns));
622
+ const preconditions = mergeStringLists(defaults?.preconditions, normalizeStringList(fromSpec?.preconditions));
623
+ const postconditions = mergeStringLists(defaults?.postconditions, normalizeStringList(fromSpec?.postconditions));
624
+ return {
625
+ ...(notes ? { notes } : {}),
626
+ ...(antiPatterns ? { antiPatterns } : {}),
627
+ ...(preconditions ? { preconditions } : {}),
628
+ ...(postconditions ? { postconditions } : {}),
629
+ };
630
+ }
631
+ function fromSpec(spec) {
632
+ const summary = typeof spec.summary === 'string' ? spec.summary.trim() : '';
633
+ const policy = spec.policy ?? toDefaultPolicy(spec);
634
+ const examples = spec.examples && spec.examples.length > 0 ? [...spec.examples] : toDefaultExamples(spec);
635
+ const docs = toNormalizedDocs(DOCS_OVERRIDES[spec.operationId], spec.docs);
636
+ return {
637
+ operationId: spec.operationId,
638
+ toolId: spec.toolId,
639
+ summary: summary || toSummary(spec.operationId),
640
+ kind: spec.kind,
641
+ sideEffect: spec.sideEffect ?? toSideEffect(spec.kind),
642
+ serviceKey: spec.serviceKey,
643
+ serviceEntity: spec.serviceEntity,
644
+ methodName: spec.methodName,
645
+ args: spec.args.map((arg) => ({ ...arg })),
646
+ ...(spec.tags ? { tags: [...spec.tags] } : {}),
647
+ ...(spec.inputSchema !== undefined ? { inputSchema: spec.inputSchema } : {}),
648
+ ...(spec.outputSchema !== undefined ? { outputSchema: spec.outputSchema } : {}),
649
+ ...(policy !== undefined ? { policy } : {}),
650
+ ...(examples.length > 0 ? { examples } : {}),
651
+ ...(docs.notes ? { notes: docs.notes } : {}),
652
+ ...(docs.antiPatterns ? { antiPatterns: docs.antiPatterns } : {}),
653
+ ...(docs.preconditions ? { preconditions: docs.preconditions } : {}),
654
+ ...(docs.postconditions ? { postconditions: docs.postconditions } : {}),
655
+ };
656
+ }
657
+ export function listDocmanOperationContracts(options) {
658
+ return listDocmanOperationSpecs(options).map(fromSpec);
659
+ }
660
+ export function getDocmanOperationContractByToolId(toolId, options) {
661
+ const operations = listDocmanOperationContracts(options);
662
+ return operations.find((operation) => operation.toolId === toolId) ?? null;
663
+ }
664
+ export function getDocmanOperationContractById(operationId, options) {
665
+ const operations = listDocmanOperationContracts(options);
666
+ return operations.find((operation) => operation.operationId === operationId) ?? null;
667
+ }