@mdbase-dev/connect-protocol 0.1.0-beta.121 → 0.1.0-beta.124

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.
@@ -0,0 +1,48 @@
1
+ import type { CollectionFileDescriptor } from "./files.js";
2
+ export declare const CHANGE_EVENT_KINDS: {
3
+ readonly "mdbase.record.created": "record.created";
4
+ readonly "mdbase.record.modified": "record.updated";
5
+ readonly "mdbase.record.deleted": "record.deleted";
6
+ readonly "mdbase.record.renamed": "record.renamed";
7
+ readonly "mdbase.type.changed": "schema.changed";
8
+ readonly "mdbase.config.changed": "config.changed";
9
+ readonly "mdbase.contract.changed": "contract.changed";
10
+ readonly "mdbase.view.changed": "view.changed";
11
+ readonly "mdbase.view_source.changed": "view.changed";
12
+ readonly "mdbase.resource.changed": "file.changed";
13
+ readonly "mdbase.file.put": "file.put";
14
+ readonly "mdbase.file.remove": "file.removed";
15
+ readonly file_put: "file.put";
16
+ readonly file_remove: "file.removed";
17
+ readonly "mdbase.collection.invalidated": "gap";
18
+ };
19
+ export type KnownCollectionChangeType = keyof typeof CHANGE_EVENT_KINDS;
20
+ /** Optional metadata: older authorities may omit fields; null means unavailable. */
21
+ export interface RecordChangePayload {
22
+ path?: string | null;
23
+ from?: string | null;
24
+ to?: string | null;
25
+ previous_revision?: string | null;
26
+ revision?: string | null;
27
+ previous_types?: string[] | null;
28
+ types?: string[] | null;
29
+ changed_fields?: string[] | null;
30
+ body_changed?: boolean | null;
31
+ before?: Record<string, unknown> | null;
32
+ after?: Record<string, unknown> | null;
33
+ }
34
+ /** Optional metadata: older authorities may omit fields; null means unavailable. */
35
+ export interface ResourceChangePayload {
36
+ name?: string | null;
37
+ path?: string | null;
38
+ previous_revision?: string | null;
39
+ revision?: string | null;
40
+ reason?: string | null;
41
+ }
42
+ /** Optional metadata: older authorities may omit fields; null means unavailable. */
43
+ export interface FileChangePayload {
44
+ file?: CollectionFileDescriptor | null;
45
+ file_id?: string | null;
46
+ previous_path?: string | null;
47
+ revision?: string | null;
48
+ }
@@ -0,0 +1,18 @@
1
+ // Generated by scripts/generate-change-events.mjs. Do not edit directly.
2
+ export const CHANGE_EVENT_KINDS = {
3
+ "mdbase.record.created": "record.created",
4
+ "mdbase.record.modified": "record.updated",
5
+ "mdbase.record.deleted": "record.deleted",
6
+ "mdbase.record.renamed": "record.renamed",
7
+ "mdbase.type.changed": "schema.changed",
8
+ "mdbase.config.changed": "config.changed",
9
+ "mdbase.contract.changed": "contract.changed",
10
+ "mdbase.view.changed": "view.changed",
11
+ "mdbase.view_source.changed": "view.changed",
12
+ "mdbase.resource.changed": "file.changed",
13
+ "mdbase.file.put": "file.put",
14
+ "mdbase.file.remove": "file.removed",
15
+ "file_put": "file.put",
16
+ "file_remove": "file.removed",
17
+ "mdbase.collection.invalidated": "gap"
18
+ };
@@ -168,6 +168,10 @@ export declare const CONNECT_PROBLEM_CATALOG: {
168
168
  readonly category: "availability";
169
169
  readonly recovery: "retry";
170
170
  };
171
+ readonly file_list_changed: {
172
+ readonly category: "conflict";
173
+ readonly recovery: "refresh";
174
+ };
171
175
  readonly file_move_failed: {
172
176
  readonly category: "internal";
173
177
  readonly recovery: "contact_support";
@@ -564,6 +568,7 @@ export interface ConnectProblemDetailsByCode {
564
568
  "file_changed_during_move": undefined;
565
569
  "file_changed_during_read": undefined;
566
570
  "file_index_warming": undefined;
571
+ "file_list_changed": undefined;
567
572
  "file_move_failed": undefined;
568
573
  "file_mutation_conflict": undefined;
569
574
  "file_not_found": undefined;
@@ -919,6 +924,12 @@ export interface ConnectProblemByCode {
919
924
  recovery: "retry";
920
925
  details?: never;
921
926
  };
927
+ "file_list_changed": ConnectProblemBase & {
928
+ code: "file_list_changed";
929
+ category: "conflict";
930
+ recovery: "refresh";
931
+ details?: never;
932
+ };
922
933
  "file_move_failed": ConnectProblemBase & {
923
934
  code: "file_move_failed";
924
935
  category: "internal";
@@ -43,6 +43,7 @@ export const CONNECT_PROBLEM_CATALOG = {
43
43
  "file_changed_during_move": { category: "conflict", recovery: "refresh" },
44
44
  "file_changed_during_read": { category: "conflict", recovery: "refresh" },
45
45
  "file_index_warming": { category: "availability", recovery: "retry" },
46
+ "file_list_changed": { category: "conflict", recovery: "refresh" },
46
47
  "file_move_failed": { category: "internal", recovery: "contact_support" },
47
48
  "file_mutation_conflict": { category: "conflict", recovery: "resolve_conflict" },
48
49
  "file_not_found": { category: "conflict", recovery: "refresh" },
package/dist/files.d.ts CHANGED
@@ -84,7 +84,24 @@ export interface ListFilesRequest {
84
84
  after?: string;
85
85
  limit?: number;
86
86
  }
87
+ export type StatFileRequest = {
88
+ protocol_version: 1;
89
+ type: "stat_file";
90
+ } & ({
91
+ path: string;
92
+ file_id?: never;
93
+ } | {
94
+ path?: never;
95
+ file_id: string;
96
+ });
97
+ export interface FileStat {
98
+ protocol_version: 1;
99
+ type: "file_stat";
100
+ file: CollectionFileDescriptor | null;
101
+ }
87
102
  export interface ListFilesPage {
103
+ /** Authority-local file implementation features, not granted actions. */
104
+ authority_capabilities?: string[];
88
105
  protocol_version: 1;
89
106
  type: "files_page";
90
107
  files: CollectionFileDescriptor[];
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import type { ConnectProblem } from "./connect-problems.generated.js";
2
+ import type { JsonObject, QueryRecord } from "./records.js";
3
+ export * from "./records.js";
2
4
  import type { ApplicationFileRequirement, LegacyApplicationFileRequirement, CollectionFileDescriptor, FileCapability } from "./files.js";
3
5
  import type { CollectionOperation } from "./operations.js";
4
6
  import type { ApplicationCapabilityRequirements, LegacyApplicationCapabilityRequirements } from "./capabilities.js";
@@ -8,6 +10,7 @@ import type { ApplicationAuthorizationProof } from "./application-authorization.
8
10
  export * from "./connect-problems.generated.js";
9
11
  export * from "./files.js";
10
12
  export * from "./operations.js";
13
+ export * from "./change-events.generated.js";
11
14
  export * from "./mutation-fingerprint.js";
12
15
  export * from "./compatibility.js";
13
16
  export * from "./capabilities.js";
@@ -631,7 +634,6 @@ export interface ConnectorCollection {
631
634
  enabled: boolean;
632
635
  contracts: CollectionContractDescriptor[];
633
636
  }
634
- export type JsonObject = Record<string, unknown>;
635
637
  export interface MdbaseDiagnostic {
636
638
  [key: string]: unknown;
637
639
  severity: "error" | "warning" | "info";
@@ -754,60 +756,6 @@ export interface SavedViewExecution<Frontmatter extends JsonObject = JsonObject>
754
756
  }>;
755
757
  };
756
758
  }
757
- export interface CollectionFileMetadata extends JsonObject {
758
- name: string;
759
- folder: string;
760
- size: number;
761
- mtime: string;
762
- tags?: string[];
763
- links?: unknown[];
764
- embeds?: unknown[];
765
- }
766
- export interface DataContractViewIdentity {
767
- id: string;
768
- version: string;
769
- digest: string;
770
- type: string;
771
- implementation_digest: string;
772
- }
773
- /**
774
- * A projected query row. Frontmatter members are optional because
775
- * `frontmatter_mode` selects which fixed-semantics representation is returned.
776
- */
777
- export interface QueryRecord<Frontmatter extends JsonObject = JsonObject> {
778
- path: string;
779
- frontmatter?: Frontmatter;
780
- effective_frontmatter?: Frontmatter;
781
- body?: string;
782
- types: string[];
783
- file: Partial<CollectionFileMetadata> & {
784
- path?: string;
785
- };
786
- values?: JsonObject;
787
- /** Present when the authority returned a normalized contract projection. */
788
- contract?: DataContractViewIdentity;
789
- }
790
- /** An authoritative record or a field-limited data-contract projection. */
791
- export interface RecordDocument<Frontmatter extends JsonObject = JsonObject> {
792
- path: string;
793
- revision: string;
794
- types: string[];
795
- frontmatter: Frontmatter;
796
- effective_frontmatter: Frontmatter;
797
- /** Omitted from contract-scoped results. */
798
- body?: string;
799
- /**
800
- * The exact UTF-8 Markdown source, including frontmatter delimiters,
801
- * comments, quoting, whitespace, line endings, and trailing newline.
802
- * Returned only when the operation requests it.
803
- */
804
- document?: string;
805
- file: Partial<CollectionFileMetadata> & {
806
- path?: string;
807
- };
808
- /** Present when the authority returned a normalized contract projection. */
809
- contract?: DataContractViewIdentity;
810
- }
811
759
  export interface CollectionTypeDescriptor {
812
760
  name: string;
813
761
  version?: number;
@@ -853,6 +801,8 @@ export interface CollectionContractImplementationDescriptor {
853
801
  binding?: JsonObject;
854
802
  }
855
803
  export interface CollectionDescription {
804
+ /** Authority-local implementation features, not permissions. Absence means legacy. */
805
+ authority_capabilities?: string[];
856
806
  protocol_version: 1;
857
807
  collection_id: string;
858
808
  display_name: string;
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { FRESH_APPLICATION_AUTHORIZATION_CAPABILITIES } from "./capabilities.js";
2
+ export * from "./records.js";
2
3
  import { YAML_DOCUMENT_RECORDS_CAPABILITY } from "./collection-setup.js";
3
4
  export * from "./connect-problems.generated.js";
4
5
  export * from "./files.js";
5
6
  export * from "./operations.js";
7
+ export * from "./change-events.generated.js";
6
8
  export * from "./mutation-fingerprint.js";
7
9
  export * from "./compatibility.js";
8
10
  export * from "./capabilities.js";
@@ -1,7 +1,7 @@
1
1
  export declare const OPERATION_CATALOG_VERSION: 1;
2
2
  export declare const COLLECTION_OPERATIONS: readonly ["describe", "changes", "read", "query", "list_views", "execute_view", "read_view_source", "create_view_source", "update_view_source", "delete_view_source", "validate", "create", "update", "delete", "rename", "read_type", "create_type", "update_type", "assess_type_pack", "apply_type_pack", "assess_collection_setup", "apply_collection_setup", "list_timers", "put_timer", "cancel_timer", "reconcile_timers", "sync"];
3
3
  export type CollectionOperation = typeof COLLECTION_OPERATIONS[number];
4
- export declare const FILE_CONTROL_MESSAGE_TYPES: readonly ["list_files", "open_file_upload", "open_file_download", "move_file", "delete_file", "get_file_transfer_status", "commit_file_upload", "abort_file_transfer"];
4
+ export declare const FILE_CONTROL_MESSAGE_TYPES: readonly ["list_files", "stat_file", "open_file_upload", "open_file_download", "move_file", "delete_file", "get_file_transfer_status", "commit_file_upload", "abort_file_transfer"];
5
5
  export type FileControlMessageType = typeof FILE_CONTROL_MESSAGE_TYPES[number];
6
6
  export type EncryptedOperation = CollectionOperation | "file_control";
7
7
  export declare const MUTATING_OPERATION_IDENTIFIERS: readonly ["create_view_source", "update_view_source", "delete_view_source", "create", "update", "delete", "rename", "create_type", "update_type", "apply_type_pack", "apply_collection_setup", "put_timer", "cancel_timer", "reconcile_timers", "sync:mutate", "file_control:open_file_upload", "file_control:move_file", "file_control:delete_file", "file_control:commit_file_upload", "file_control:abort_file_transfer"];
@@ -31,6 +31,7 @@ export const COLLECTION_OPERATIONS = [
31
31
  ];
32
32
  export const FILE_CONTROL_MESSAGE_TYPES = [
33
33
  "list_files",
34
+ "stat_file",
34
35
  "open_file_upload",
35
36
  "open_file_download",
36
37
  "move_file",
@@ -99,6 +100,7 @@ const COLLECTION_INPUT_SCHEMA_VERSIONS = {
99
100
  };
100
101
  const FILE_CONTROL_INPUT_SCHEMA_VERSIONS = {
101
102
  "list_files": 1,
103
+ "stat_file": 1,
102
104
  "open_file_upload": 1,
103
105
  "open_file_download": 1,
104
106
  "move_file": 1,
@@ -0,0 +1,108 @@
1
+ export type JsonObject = Record<string, unknown>;
2
+ export interface CollectionFileMetadata extends JsonObject {
3
+ name: string;
4
+ folder: string;
5
+ size: number;
6
+ mtime: string;
7
+ tags?: string[];
8
+ links?: unknown[];
9
+ embeds?: unknown[];
10
+ }
11
+ export interface DataContractViewIdentity {
12
+ id: string;
13
+ version: string;
14
+ digest: string;
15
+ type: string;
16
+ implementation_digest: string;
17
+ }
18
+ /** Frontmatter members depend on the selected frontmatter_mode. */
19
+ export interface QueryRecord<Frontmatter extends JsonObject = JsonObject> {
20
+ path: string;
21
+ /** Exact-source token; absent on authorities predating query-record-revisions-v1. */
22
+ revision?: string;
23
+ frontmatter?: Frontmatter;
24
+ effective_frontmatter?: Frontmatter;
25
+ body?: string;
26
+ types: string[];
27
+ file: Partial<CollectionFileMetadata> & {
28
+ path?: string;
29
+ };
30
+ values?: JsonObject;
31
+ /** Present when the authority returned a normalized contract projection. */
32
+ contract?: DataContractViewIdentity;
33
+ }
34
+ export declare const MAX_READ_MANY_PATHS = 100;
35
+ /** Ceiling for the serialized batch operation envelope; callers must split on overflow. */
36
+ export declare const MAX_READ_MANY_RESPONSE_BYTES: number;
37
+ export interface DataContractSelector {
38
+ id: string;
39
+ version: string;
40
+ type?: string;
41
+ }
42
+ /** Existing read operation: exactly one target form; batch defaults differ from point reads. */
43
+ export type ReadInput = ({
44
+ path: string;
45
+ paths?: never;
46
+ } | {
47
+ path?: never;
48
+ paths: string[];
49
+ }) & {
50
+ contract?: DataContractSelector;
51
+ /** Batch default: true. Single-path defaults remain unchanged. */
52
+ include_body?: boolean;
53
+ /** Batch default: false. Contract projections cannot request exact source. */
54
+ include_document?: boolean;
55
+ };
56
+ export type ReadManyDocumentItem<Frontmatter extends JsonObject = JsonObject> = {
57
+ path: string;
58
+ status: "found";
59
+ record: RecordDocument<Frontmatter>;
60
+ } | {
61
+ path: string;
62
+ status: "missing";
63
+ } | {
64
+ path: string;
65
+ status: "error";
66
+ error: {
67
+ code: string;
68
+ message: string;
69
+ };
70
+ };
71
+ export interface ReadManyDocumentsResult<Frontmatter extends JsonObject = JsonObject> {
72
+ /** One ordered item per input occurrence, including duplicates. */
73
+ items: Array<ReadManyDocumentItem<Frontmatter>>;
74
+ }
75
+ /** Negotiated narrow row; omitted document fields are not empty fields. */
76
+ export interface QueryMetadataRecord {
77
+ path: string;
78
+ types: string[];
79
+ revision: string;
80
+ values: JsonObject;
81
+ contract?: DataContractViewIdentity;
82
+ }
83
+ export interface QueryMetadataResult {
84
+ output: "metadata";
85
+ results: QueryMetadataRecord[];
86
+ meta?: JsonObject;
87
+ }
88
+ /** An authoritative record or a field-limited data-contract projection. */
89
+ export interface RecordDocument<Frontmatter extends JsonObject = JsonObject> {
90
+ path: string;
91
+ revision: string;
92
+ types: string[];
93
+ frontmatter: Frontmatter;
94
+ effective_frontmatter: Frontmatter;
95
+ /** Omitted from contract-scoped results. */
96
+ body?: string;
97
+ /**
98
+ * The exact UTF-8 Markdown source, including frontmatter delimiters,
99
+ * comments, quoting, whitespace, line endings, and trailing newline.
100
+ * Returned only when the operation requests it.
101
+ */
102
+ document?: string;
103
+ file: Partial<CollectionFileMetadata> & {
104
+ path?: string;
105
+ };
106
+ /** Present when the authority returned a normalized contract projection. */
107
+ contract?: DataContractViewIdentity;
108
+ }
@@ -0,0 +1,3 @@
1
+ export const MAX_READ_MANY_PATHS = 100;
2
+ /** Ceiling for the serialized batch operation envelope; callers must split on overflow. */
3
+ export const MAX_READ_MANY_RESPONSE_BYTES = 8 * 1024 * 1024;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdbase-dev/connect-protocol",
3
- "version": "0.1.0-beta.121",
3
+ "version": "0.1.0-beta.124",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
39
- "test": "node --test test/*.test.mjs && node ../../scripts/generate-connect-problems.mjs --check && node ../../scripts/generate-operation-catalog.mjs --check && node ../../scripts/generate-application-capabilities.mjs --check",
39
+ "test": "node --test test/*.test.mjs && node ../../scripts/generate-change-events.mjs --check && node ../../scripts/generate-connect-problems.mjs --check && node ../../scripts/generate-operation-catalog.mjs --check && node ../../scripts/generate-application-capabilities.mjs --check",
40
40
  "typecheck": "tsc -p tsconfig.json --noEmit"
41
41
  }
42
42
  }
@@ -0,0 +1,48 @@
1
+ {
2
+ "version": 1,
3
+ "events": {
4
+ "mdbase.record.created": "record.created",
5
+ "mdbase.record.modified": "record.updated",
6
+ "mdbase.record.deleted": "record.deleted",
7
+ "mdbase.record.renamed": "record.renamed",
8
+ "mdbase.type.changed": "schema.changed",
9
+ "mdbase.config.changed": "config.changed",
10
+ "mdbase.contract.changed": "contract.changed",
11
+ "mdbase.view.changed": "view.changed",
12
+ "mdbase.view_source.changed": "view.changed",
13
+ "mdbase.resource.changed": "file.changed",
14
+ "mdbase.file.put": "file.put",
15
+ "mdbase.file.remove": "file.removed",
16
+ "file_put": "file.put",
17
+ "file_remove": "file.removed",
18
+ "mdbase.collection.invalidated": "gap"
19
+ },
20
+ "payloads": {
21
+ "RecordChangePayload": {
22
+ "path": "string",
23
+ "from": "string",
24
+ "to": "string",
25
+ "previous_revision": "string",
26
+ "revision": "string",
27
+ "previous_types": "strings",
28
+ "types": "strings",
29
+ "changed_fields": "strings",
30
+ "body_changed": "boolean",
31
+ "before": "object",
32
+ "after": "object"
33
+ },
34
+ "ResourceChangePayload": {
35
+ "name": "string",
36
+ "path": "string",
37
+ "previous_revision": "string",
38
+ "revision": "string",
39
+ "reason": "string"
40
+ },
41
+ "FileChangePayload": {
42
+ "file": "file",
43
+ "file_id": "string",
44
+ "previous_path": "string",
45
+ "revision": "string"
46
+ }
47
+ }
48
+ }
@@ -1928,6 +1928,46 @@
1928
1928
  }
1929
1929
  }
1930
1930
  },
1931
+ {
1932
+ "type": "object",
1933
+ "additionalProperties": false,
1934
+ "required": [
1935
+ "problem_version",
1936
+ "code",
1937
+ "category",
1938
+ "recovery",
1939
+ "message"
1940
+ ],
1941
+ "properties": {
1942
+ "problem_version": {
1943
+ "const": 1
1944
+ },
1945
+ "code": {
1946
+ "const": "file_list_changed"
1947
+ },
1948
+ "category": {
1949
+ "const": "conflict"
1950
+ },
1951
+ "recovery": {
1952
+ "const": "refresh"
1953
+ },
1954
+ "message": {
1955
+ "type": "string",
1956
+ "minLength": 1
1957
+ },
1958
+ "operation_outcome": {
1959
+ "enum": [
1960
+ "not_sent",
1961
+ "rejected",
1962
+ "unknown"
1963
+ ]
1964
+ },
1965
+ "trace_id": {
1966
+ "type": "string",
1967
+ "minLength": 1
1968
+ }
1969
+ }
1970
+ },
1931
1971
  {
1932
1972
  "type": "object",
1933
1973
  "additionalProperties": false,
@@ -194,6 +194,7 @@
194
194
  "file_changed_during_move": { "category": "conflict", "recovery": "refresh" },
195
195
  "file_changed_during_read": { "category": "conflict", "recovery": "refresh" },
196
196
  "file_index_warming": { "category": "availability", "recovery": "retry" },
197
+ "file_list_changed": { "category": "conflict", "recovery": "refresh" },
197
198
  "file_move_failed": { "category": "internal", "recovery": "contact_support" },
198
199
  "file_mutation_conflict": { "category": "conflict", "recovery": "resolve_conflict" },
199
200
  "file_not_found": { "category": "conflict", "recovery": "refresh" },
@@ -674,12 +674,96 @@
674
674
  "display_name": { "type": "string", "minLength": 1 },
675
675
  "spec_version": { "type": "string", "minLength": 1 },
676
676
  "operations": { "type": "array", "uniqueItems": true, "items": { "$ref": "#/$defs/operation" } },
677
+ "authority_capabilities": { "type": "array", "items": { "type": "string" } },
677
678
  "change_cursor": { "type": "integer", "minimum": 0 },
678
679
  "types": { "type": "array", "items": { "$ref": "#/$defs/collectionType" } },
679
680
  "contracts": { "type": "array", "items": { "$ref": "#/$defs/collectionContract" } },
680
681
  "configuration": { "type": "object", "description": "Canonical portable collection settings. Extension and implementation-specific values are omitted." }
681
682
  }
682
683
  },
684
+ "dataContractSelector": {
685
+ "type": "object", "additionalProperties": false,
686
+ "required": ["id", "version"],
687
+ "properties": {
688
+ "id": { "type": "string" }, "version": { "type": "string" }, "type": { "type": "string" }
689
+ }
690
+ },
691
+ "readInput": {
692
+ "type": "object", "additionalProperties": false,
693
+ "properties": {
694
+ "path": { "type": "string", "minLength": 1 },
695
+ "paths": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "type": "string", "minLength": 1 } },
696
+ "include_body": { "type": "boolean", "description": "Batch default true; point-read defaults unchanged." },
697
+ "include_document": { "type": "boolean", "default": false },
698
+ "contract": { "$ref": "#/$defs/dataContractSelector" }
699
+ },
700
+ "oneOf": [{ "required": ["path"] }, { "required": ["paths"] }],
701
+ "allOf": [{ "if": { "required": ["contract"] }, "then": { "properties": { "include_document": { "const": false } } } }]
702
+ },
703
+ "recordDocument": {
704
+ "type": "object", "additionalProperties": false,
705
+ "required": ["path", "revision", "types", "frontmatter", "effective_frontmatter", "file"],
706
+ "properties": {
707
+ "path": { "type": "string" }, "revision": { "type": "string" },
708
+ "types": { "type": "array", "items": { "type": "string" } },
709
+ "frontmatter": { "type": "object" }, "effective_frontmatter": { "type": "object" },
710
+ "body": { "type": "string" }, "document": { "type": "string" },
711
+ "file": { "type": "object" }, "contract": { "type": "object" }
712
+ }
713
+ },
714
+ "readManyDocumentItem": {
715
+ "oneOf": [
716
+ {
717
+ "type": "object", "additionalProperties": false, "required": ["path", "status", "record"],
718
+ "properties": { "path": { "type": "string" }, "status": { "const": "found" }, "record": { "$ref": "#/$defs/recordDocument" } }
719
+ },
720
+ {
721
+ "type": "object", "additionalProperties": false, "required": ["path", "status"],
722
+ "properties": { "path": { "type": "string" }, "status": { "const": "missing" } }
723
+ },
724
+ {
725
+ "type": "object", "additionalProperties": false, "required": ["path", "status", "error"],
726
+ "properties": {
727
+ "path": { "type": "string" }, "status": { "const": "error" },
728
+ "error": {
729
+ "type": "object", "additionalProperties": false, "required": ["code", "message"],
730
+ "properties": { "code": { "type": "string" }, "message": { "type": "string" } }
731
+ }
732
+ }
733
+ }
734
+ ]
735
+ },
736
+ "readManyDocumentsResult": {
737
+ "description": "Ordered items including duplicates. Serialized operation envelope maximum 8 MiB; overflow fails explicitly and asks callers to split, never truncates.",
738
+ "type": "object", "additionalProperties": false, "required": ["items"],
739
+ "properties": { "items": { "type": "array", "maxItems": 100, "items": { "$ref": "#/$defs/readManyDocumentItem" } } }
740
+ },
741
+ "queryRecord": {
742
+ "type": "object", "additionalProperties": false, "required": ["path", "types", "file"],
743
+ "properties": {
744
+ "path": { "type": "string" }, "revision": { "type": "string" },
745
+ "types": { "type": "array", "items": { "type": "string" } },
746
+ "frontmatter": { "type": "object" }, "effective_frontmatter": { "type": "object" },
747
+ "body": { "type": "string" }, "values": { "type": "object" },
748
+ "file": { "type": "object" }, "contract": { "type": "object" }
749
+ }
750
+ },
751
+ "queryMetadataRecord": {
752
+ "type": "object", "additionalProperties": false, "required": ["path", "types", "revision", "values"],
753
+ "properties": {
754
+ "path": { "type": "string" }, "revision": { "type": "string" },
755
+ "types": { "type": "array", "items": { "type": "string" } },
756
+ "values": { "type": "object" }, "contract": { "type": "object" }
757
+ }
758
+ },
759
+ "queryMetadataResult": {
760
+ "type": "object", "additionalProperties": false, "required": ["output", "results"],
761
+ "properties": {
762
+ "output": { "const": "metadata" },
763
+ "results": { "type": "array", "items": { "$ref": "#/$defs/queryMetadataRecord" } },
764
+ "meta": { "type": "object" }
765
+ }
766
+ },
683
767
  "collectionType": {
684
768
  "type": "object",
685
769
  "additionalProperties": false,
@@ -9,6 +9,8 @@
9
9
  { "$ref": "#/$defs/fileDescriptor" },
10
10
  { "$ref": "#/$defs/listFilesRequest" },
11
11
  { "$ref": "#/$defs/listFilesPage" },
12
+ { "$ref": "#/$defs/statFileRequest" },
13
+ { "$ref": "#/$defs/fileStat" },
12
14
  { "$ref": "#/$defs/openUploadRequest" },
13
15
  { "$ref": "#/$defs/openDownloadRequest" },
14
16
  { "$ref": "#/$defs/moveFileRequest" },
@@ -161,7 +163,30 @@
161
163
  "protocol_version": { "const": 1 },
162
164
  "type": { "const": "files_page" },
163
165
  "files": { "type": "array", "items": { "$ref": "#/$defs/fileDescriptor" } },
164
- "next": { "type": "string", "minLength": 1 }
166
+ "next": { "type": "string", "minLength": 1 },
167
+ "authority_capabilities": { "type": "array", "items": { "type": "string" } }
168
+ }
169
+ },
170
+ "statFileRequest": {
171
+ "type": "object",
172
+ "additionalProperties": false,
173
+ "required": ["protocol_version", "type"],
174
+ "properties": {
175
+ "protocol_version": { "const": 1 },
176
+ "type": { "const": "stat_file" },
177
+ "path": { "$ref": "#/$defs/path" },
178
+ "file_id": { "$ref": "#/$defs/uuid" }
179
+ },
180
+ "oneOf": [{ "required": ["path"] }, { "required": ["file_id"] }]
181
+ },
182
+ "fileStat": {
183
+ "type": "object",
184
+ "additionalProperties": false,
185
+ "required": ["protocol_version", "type", "file"],
186
+ "properties": {
187
+ "protocol_version": { "const": 1 },
188
+ "type": { "const": "file_stat" },
189
+ "file": { "oneOf": [{ "$ref": "#/$defs/fileDescriptor" }, { "type": "null" }] }
165
190
  }
166
191
  },
167
192
  "openUploadRequest": {
@@ -16,6 +16,7 @@
16
16
  "limit": { "type": "integer", "minimum": 0 },
17
17
  "offset": { "type": "integer", "minimum": 0 },
18
18
  "include_body": { "type": "boolean", "default": false },
19
+ "output": { "const": "metadata" },
19
20
  "frontmatter_mode": {
20
21
  "enum": ["effective", "persisted", "both"],
21
22
  "default": "effective"
@@ -25,6 +26,10 @@
25
26
  "^x-[A-Za-z][A-Za-z0-9._:-]{0,127}$": { "$ref": "#/$defs/extension" }
26
27
  },
27
28
  "additionalProperties": false,
29
+ "allOf": [{
30
+ "if": { "required": ["output"], "properties": { "output": { "const": "metadata" } } },
31
+ "then": { "properties": { "include_body": { "const": false } } }
32
+ }],
28
33
  "$defs": {
29
34
  "identifier": {
30
35
  "type": "string",
@@ -31,6 +31,7 @@
31
31
  ],
32
32
  "file_control_messages": [
33
33
  { "id": "list_files", "input_schema_version": 1, "mutation": false },
34
+ { "id": "stat_file", "input_schema_version": 1, "mutation": false },
34
35
  { "id": "open_file_upload", "input_schema_version": 1, "mutation": true },
35
36
  { "id": "open_file_download", "input_schema_version": 1, "mutation": false },
36
37
  { "id": "move_file", "input_schema_version": 1, "mutation": true },
@@ -414,6 +414,23 @@
414
414
  "schema_version": 1,
415
415
  "identifier": null
416
416
  },
417
+ {
418
+ "operation": "file_control",
419
+ "input": {
420
+ "type": "stat_file"
421
+ },
422
+ "schema_version": 1,
423
+ "identifier": null
424
+ },
425
+ {
426
+ "operation": "file_control",
427
+ "input": {
428
+ "type": "stat_file",
429
+ "dry_run": true
430
+ },
431
+ "schema_version": 1,
432
+ "identifier": null
433
+ },
417
434
  {
418
435
  "operation": "file_control",
419
436
  "input": {