Add activated workspace reflection and Studio definition watches
Expose bounded snapshot-bound definition reads and latest-only watches from the serving checked bundle. Add checked reflection dependency ports, generated SDK bindings and selector-scoped invocation authority. Move Studio factory, contract and query discovery to public reflection inventories. Share an active-definition watch across canvas and standalone routes and invalidate/reload on epoch changes instead of polling GetWorkspace. Document the API and deferred scope; cover compiler/codegen, SDK injection, transport authorization, activation publication, pagination and reconnect behavior. Keep all work local; no deployment or publication.
This commit is contained in:
@@ -207,7 +207,8 @@ dependencyBlock
|
|||||||
;
|
;
|
||||||
|
|
||||||
dependencyPort
|
dependencyPort
|
||||||
: STATE identifier ID stringLiteral COLON valueType primitiveList SEMI
|
: REFLECTION identifier ID stringLiteral LBRACK identifierList RBRACK SEMI
|
||||||
|
| STATE identifier ID stringLiteral COLON valueType primitiveList SEMI
|
||||||
| EDGE identifier ID stringLiteral COLON cardinality targetConstraint primitiveList SEMI
|
| EDGE identifier ID stringLiteral COLON cardinality targetConstraint primitiveList SEMI
|
||||||
| INTERFACE identifier ID stringLiteral COLON identifier typeArguments? SEMI
|
| INTERFACE identifier ID stringLiteral COLON identifier typeArguments? SEMI
|
||||||
| CONSTRUCTOR identifier ID stringLiteral COLON identifier (INPUT valueType)? SEMI
|
| CONSTRUCTOR identifier ID stringLiteral COLON identifier (INPUT valueType)? SEMI
|
||||||
@@ -325,7 +326,8 @@ dependencyBindingBlock
|
|||||||
;
|
;
|
||||||
|
|
||||||
dependencyBinding
|
dependencyBinding
|
||||||
: identifier TO STATE identifier (VIA EDGE identifier DOT identifier)? SEMI
|
: identifier TO WORKSPACE REFLECTION LBRACK identifierList RBRACK SEMI
|
||||||
|
| identifier TO STATE identifier (VIA EDGE identifier DOT identifier)? SEMI
|
||||||
| identifier TO EDGE identifier DOT identifier (VIA EDGE identifier DOT identifier)? SEMI
|
| identifier TO EDGE identifier DOT identifier (VIA EDGE identifier DOT identifier)? SEMI
|
||||||
| identifier TO INTERFACE identifier typeArguments? (VIA EDGE identifier DOT identifier)? SEMI
|
| identifier TO INTERFACE identifier typeArguments? (VIA EDGE identifier DOT identifier)? SEMI
|
||||||
| identifier TO CONSTRUCTOR identifier SEMI
|
| identifier TO CONSTRUCTOR identifier SEMI
|
||||||
@@ -397,6 +399,8 @@ jsonArray
|
|||||||
|
|
||||||
identifier
|
identifier
|
||||||
: IDENTIFIER
|
: IDENTIFIER
|
||||||
|
| INTERFACES
|
||||||
|
| REFLECTION
|
||||||
| SOURCE
|
| SOURCE
|
||||||
| QUERY
|
| QUERY
|
||||||
| SPECIALIZE
|
| SPECIALIZE
|
||||||
@@ -423,6 +427,7 @@ RESULT_BYTES: 'result-bytes';
|
|||||||
RPC_CALLS: 'rpc-calls';
|
RPC_CALLS: 'rpc-calls';
|
||||||
DEADLINE_MS: 'deadline-ms';
|
DEADLINE_MS: 'deadline-ms';
|
||||||
QUERY: 'query';
|
QUERY: 'query';
|
||||||
|
REFLECTION: 'reflection';
|
||||||
SPECIALIZE: 'specialize';
|
SPECIALIZE: 'specialize';
|
||||||
ROOT: 'root';
|
ROOT: 'root';
|
||||||
DOCUMENT: 'document';
|
DOCUMENT: 'document';
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import "quixos/refs.proto";
|
|||||||
import "quixos/runtime.proto";
|
import "quixos/runtime.proto";
|
||||||
|
|
||||||
service OrchestratorRuntime {
|
service OrchestratorRuntime {
|
||||||
|
rpc ReadDefinitions(DefinitionRequest) returns (DefinitionPage);
|
||||||
|
rpc WatchDefinitions(DefinitionRequest) returns (stream DefinitionPage);
|
||||||
rpc ExecuteQuery(camino.QueryRequest) returns (camino.QueryResponse);
|
rpc ExecuteQuery(camino.QueryRequest) returns (camino.QueryResponse);
|
||||||
rpc WatchQuery(camino.QueryRequest) returns (stream QueryEvent);
|
rpc WatchQuery(camino.QueryRequest) returns (stream QueryEvent);
|
||||||
rpc TryConform(TryConformRequest) returns (TryConformResponse);
|
rpc TryConform(TryConformRequest) returns (TryConformResponse);
|
||||||
@@ -26,6 +28,83 @@ service OrchestratorRuntime {
|
|||||||
rpc CloseActivation(CloseActivationRequest) returns (CloseActivationResponse);
|
rpc CloseActivation(CloseActivationRequest) returns (CloseActivationResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Activated definitions, not runtime metrics or object data. Nested type JSON
|
||||||
|
// uses the compiler's canonical ValueType/InterfaceRevision public contracts.
|
||||||
|
message DefinitionSelector {
|
||||||
|
string kind = 1; // active | atoms | interfaces | conformances | queries | indexes
|
||||||
|
repeated string ids = 2;
|
||||||
|
string atom_id = 3;
|
||||||
|
string interface_revision_id = 4;
|
||||||
|
string package_revision_id = 5;
|
||||||
|
}
|
||||||
|
message DefinitionIdentity {
|
||||||
|
string workspace_id = 1;
|
||||||
|
string workspace_revision_id = 2;
|
||||||
|
string source_root_commit = 3;
|
||||||
|
string workspace_epoch = 4;
|
||||||
|
string definition_digest = 5;
|
||||||
|
}
|
||||||
|
message DefinitionRequest {
|
||||||
|
DefinitionSelector selector = 1;
|
||||||
|
uint32 first = 2; // 1..100; 0 uses 50
|
||||||
|
string after = 3;
|
||||||
|
string snapshot = 4; // issued definition_digest; current serving snapshot only
|
||||||
|
string workspace_id = 5; // required for injected package authority
|
||||||
|
string workspace_epoch = 6; // required for invocation-bound package calls
|
||||||
|
}
|
||||||
|
message ReflectedAtom {
|
||||||
|
string id = 1;
|
||||||
|
string display_name = 2;
|
||||||
|
string constructor_input_type_json = 3;
|
||||||
|
}
|
||||||
|
message ReflectedInterface {
|
||||||
|
string id = 1;
|
||||||
|
string interface_id = 2;
|
||||||
|
string display_name = 3;
|
||||||
|
string contract_json = 4; // canonical interface contract, excluding source location
|
||||||
|
}
|
||||||
|
message ReflectedConformance {
|
||||||
|
string id = 1;
|
||||||
|
string atom_id = 2;
|
||||||
|
string interface_revision_id = 3;
|
||||||
|
string definition_id = 4;
|
||||||
|
repeated string operation_ids = 5;
|
||||||
|
repeated ClassCapability class_capabilities = 6;
|
||||||
|
bool instance = 7;
|
||||||
|
}
|
||||||
|
message ReflectedQuery {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string package_revision_id = 3;
|
||||||
|
string definition_digest = 4;
|
||||||
|
string binding_digest = 5;
|
||||||
|
string root_kind = 6;
|
||||||
|
string interface_revision_id = 7;
|
||||||
|
string variables_type_json = 8;
|
||||||
|
string output_type_json = 9;
|
||||||
|
string effects_json = 10;
|
||||||
|
bool watch = 11;
|
||||||
|
WorkspaceQueryScope workspace_scope = 12;
|
||||||
|
}
|
||||||
|
message ReflectedIndex {
|
||||||
|
string id = 1;
|
||||||
|
string contract_json = 2;
|
||||||
|
}
|
||||||
|
message DefinitionRecord {
|
||||||
|
oneof definition {
|
||||||
|
ReflectedAtom atom = 1;
|
||||||
|
ReflectedInterface interface = 2;
|
||||||
|
ReflectedConformance conformance = 3;
|
||||||
|
ReflectedQuery query = 4;
|
||||||
|
ReflectedIndex index = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message DefinitionPage {
|
||||||
|
DefinitionIdentity identity = 1;
|
||||||
|
repeated DefinitionRecord records = 2;
|
||||||
|
string next_cursor = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message QueryEvent {
|
message QueryEvent {
|
||||||
string run_id = 1;
|
string run_id = 1;
|
||||||
uint64 sequence = 2;
|
uint64 sequence = 2;
|
||||||
|
|||||||
@@ -45,12 +45,19 @@ message InjectedDependency {
|
|||||||
string constructor_atom_id = 5;
|
string constructor_atom_id = 5;
|
||||||
string query_id = 7;
|
string query_id = 7;
|
||||||
WorkspaceQueryDependency workspace_query = 8;
|
WorkspaceQueryDependency workspace_query = 8;
|
||||||
|
ReflectionDependency reflection = 9;
|
||||||
}
|
}
|
||||||
// Defaults to the invocation receiver. A checked dependency traversal can
|
// Defaults to the invocation receiver. A checked dependency traversal can
|
||||||
// select a related object explicitly before the package runtime starts.
|
// select a related object explicitly before the package runtime starts.
|
||||||
string object_id = 6;
|
string object_id = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ReflectionDependency {
|
||||||
|
string workspace_id = 1;
|
||||||
|
string workspace_epoch = 2;
|
||||||
|
repeated string selectors = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// Scope evidence is not authority by itself. The caller must also hold the
|
// Scope evidence is not authority by itself. The caller must also hold the
|
||||||
// matching workspace-query grant (or the authenticated workspace user grant).
|
// matching workspace-query grant (or the authenticated workspace user grant).
|
||||||
message WorkspaceQueryScope {
|
message WorkspaceQueryScope {
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ export const genericImplementationType = (
|
|||||||
const requirement = entry.requirement,
|
const requirement = entry.requirement,
|
||||||
scope = rootScope();
|
scope = rootScope();
|
||||||
switch (requirement.kind) {
|
switch (requirement.kind) {
|
||||||
|
case "reflection":
|
||||||
|
return `QxReflectionPort<${requirement.selectors.map((value) => JSON.stringify(value)).join(" | ")}>`;
|
||||||
case "state":
|
case "state":
|
||||||
return object([
|
return object([
|
||||||
...requirement.primitives.map((primitive): [string, string] => {
|
...requirement.primitives.map((primitive): [string, string] => {
|
||||||
|
|||||||
@@ -144,6 +144,11 @@ export const generateTypeScriptBindings = (
|
|||||||
const port = (entry: DependencyPort): { type: string; spec: unknown } => {
|
const port = (entry: DependencyPort): { type: string; spec: unknown } => {
|
||||||
const requirement = entry.requirement;
|
const requirement = entry.requirement;
|
||||||
switch (requirement.kind) {
|
switch (requirement.kind) {
|
||||||
|
case "reflection":
|
||||||
|
return {
|
||||||
|
type: `QxReflectionPort<${requirement.selectors.map((value) => q(value)).join(" | ")}>`,
|
||||||
|
spec: { kind: "reflection", id: entry.id, selectors: requirement.selectors },
|
||||||
|
};
|
||||||
case "query": {
|
case "query": {
|
||||||
const query = schema.packages
|
const query = schema.packages
|
||||||
.find((candidate) => candidate.revisionId === requirement.packageRevisionId)
|
.find((candidate) => candidate.revisionId === requirement.packageRevisionId)
|
||||||
@@ -378,6 +383,7 @@ export const generateTypeScriptBindings = (
|
|||||||
"RelationshipCollection",
|
"RelationshipCollection",
|
||||||
"RelationshipEntry",
|
"RelationshipEntry",
|
||||||
"QxQuerySnapshot",
|
"QxQuerySnapshot",
|
||||||
|
"QxReflectionPort",
|
||||||
"QxQueryDescriptor",
|
"QxQueryDescriptor",
|
||||||
].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures));
|
].filter((name) => new RegExp(`\\b${name}\\b`).test(signatures));
|
||||||
return (
|
return (
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,257 +3,259 @@ RESULT_BYTES=2
|
|||||||
RPC_CALLS=3
|
RPC_CALLS=3
|
||||||
DEADLINE_MS=4
|
DEADLINE_MS=4
|
||||||
QUERY=5
|
QUERY=5
|
||||||
SPECIALIZE=6
|
REFLECTION=6
|
||||||
ROOT=7
|
SPECIALIZE=7
|
||||||
DOCUMENT=8
|
ROOT=8
|
||||||
FRAGMENTS=9
|
DOCUMENT=9
|
||||||
VIEW=10
|
FRAGMENTS=10
|
||||||
MAX=11
|
VIEW=11
|
||||||
ALLOW=12
|
MAX=12
|
||||||
POLL=13
|
ALLOW=13
|
||||||
QUERYABLE=14
|
POLL=14
|
||||||
RPC=15
|
QUERYABLE=15
|
||||||
QUERY_REASON=16
|
RPC=16
|
||||||
TYPE=17
|
QUERY_REASON=17
|
||||||
OBJECT=18
|
TYPE=18
|
||||||
STORABLE=19
|
OBJECT=19
|
||||||
IMPLEMENTS=20
|
STORABLE=20
|
||||||
REF=21
|
IMPLEMENTS=21
|
||||||
FRAGMENT=22
|
REF=22
|
||||||
IMPORT=23
|
FRAGMENT=23
|
||||||
EXTERNAL=24
|
IMPORT=24
|
||||||
ATOM=25
|
EXTERNAL=25
|
||||||
INTERFACE=26
|
ATOM=26
|
||||||
INTERFACES=27
|
INTERFACE=27
|
||||||
PACKAGE=28
|
INTERFACES=28
|
||||||
VALUE=29
|
PACKAGE=29
|
||||||
RELATION=30
|
VALUE=30
|
||||||
OPERATION=31
|
RELATION=31
|
||||||
FUNCTION=32
|
OPERATION=32
|
||||||
CONSTRUCTOR=33
|
FUNCTION=33
|
||||||
CONSTRUCTS=34
|
CONSTRUCTOR=34
|
||||||
INPUT=35
|
CONSTRUCTS=35
|
||||||
CONFORM=36
|
INPUT=36
|
||||||
AS=37
|
CONFORM=37
|
||||||
BIND=38
|
AS=38
|
||||||
STATIC=39
|
BIND=39
|
||||||
TO=40
|
STATIC=40
|
||||||
PRIVATE=41
|
TO=41
|
||||||
SHARED=42
|
PRIVATE=42
|
||||||
STATE=43
|
SHARED=43
|
||||||
EDGE=44
|
STATE=44
|
||||||
PROJECTION=45
|
EDGE=45
|
||||||
WITH=46
|
PROJECTION=46
|
||||||
USING=47
|
WITH=47
|
||||||
VIA=48
|
USING=48
|
||||||
MATERIALIZE=49
|
VIA=49
|
||||||
IF=50
|
MATERIALIZE=50
|
||||||
ABSENT=51
|
IF=51
|
||||||
ON=52
|
ABSENT=52
|
||||||
POLICY=53
|
ON=53
|
||||||
DEFAULT=54
|
POLICY=54
|
||||||
SOURCE=55
|
DEFAULT=55
|
||||||
REPOSITORY=56
|
SOURCE=56
|
||||||
COMMIT=57
|
REPOSITORY=57
|
||||||
REVISION=58
|
COMMIT=58
|
||||||
SEMANTIC_MAJOR=59
|
REVISION=59
|
||||||
ON_DELETE=60
|
SEMANTIC_MAJOR=60
|
||||||
RETAIN_OTHER=61
|
ON_DELETE=61
|
||||||
KEYED=62
|
RETAIN_OTHER=62
|
||||||
PUBLIC_TRAVERSAL=63
|
KEYED=63
|
||||||
ID=64
|
PUBLIC_TRAVERSAL=64
|
||||||
DOC=65
|
ID=65
|
||||||
MODE=66
|
DOC=66
|
||||||
EMITS=67
|
MODE=67
|
||||||
RECEIVER=68
|
EMITS=68
|
||||||
REQUIRES=69
|
RECEIVER=69
|
||||||
ANY=70
|
REQUIRES=70
|
||||||
GET=71
|
ANY=71
|
||||||
SET=72
|
GET=72
|
||||||
WATCH=73
|
SET=73
|
||||||
START=74
|
WATCH=74
|
||||||
STOP=75
|
START=75
|
||||||
READ=76
|
STOP=76
|
||||||
WRITE=77
|
READ=77
|
||||||
RESOLVE=78
|
WRITE=78
|
||||||
CONNECT=79
|
RESOLVE=79
|
||||||
DISCONNECT=80
|
CONNECT=80
|
||||||
CALL=81
|
DISCONNECT=81
|
||||||
WATCH_START=82
|
CALL=82
|
||||||
WATCH_STOP=83
|
WATCH_START=83
|
||||||
SUBSCRIBE=84
|
WATCH_STOP=84
|
||||||
UNSUBSCRIBE=85
|
SUBSCRIBE=85
|
||||||
OPTIMISTIC_REGISTER=86
|
UNSUBSCRIBE=86
|
||||||
CRDT=87
|
OPTIMISTIC_REGISTER=87
|
||||||
OPTIONAL_ONE=88
|
CRDT=88
|
||||||
EXACTLY_ONE=89
|
OPTIONAL_ONE=89
|
||||||
MANY_UNIQUE=90
|
EXACTLY_ONE=90
|
||||||
MANY=91
|
MANY_UNIQUE=91
|
||||||
ORDERED=92
|
MANY=92
|
||||||
UNIT=93
|
ORDERED=93
|
||||||
WATCH_HANDLE=94
|
UNIT=94
|
||||||
MESSAGE=95
|
WATCH_HANDLE=95
|
||||||
ATOM_REF=96
|
MESSAGE=96
|
||||||
INTERFACE_REF=97
|
ATOM_REF=97
|
||||||
OPTIONAL=98
|
INTERFACE_REF=98
|
||||||
LIST=99
|
OPTIONAL=99
|
||||||
RECORD=100
|
LIST=100
|
||||||
BOOL=101
|
RECORD=101
|
||||||
BYTES=102
|
BOOL=102
|
||||||
DOUBLE=103
|
BYTES=103
|
||||||
INT32=104
|
DOUBLE=104
|
||||||
INT64=105
|
INT32=105
|
||||||
STRING=106
|
INT64=106
|
||||||
UINT32=107
|
STRING=107
|
||||||
UINT64=108
|
UINT32=108
|
||||||
TRUE=109
|
UINT64=109
|
||||||
FALSE=110
|
TRUE=110
|
||||||
NULL=111
|
FALSE=111
|
||||||
ARROW=112
|
NULL=112
|
||||||
COLON=113
|
ARROW=113
|
||||||
SEMI=114
|
COLON=114
|
||||||
COMMA=115
|
SEMI=115
|
||||||
DOT=116
|
COMMA=116
|
||||||
LBRACE=117
|
DOT=117
|
||||||
RBRACE=118
|
LBRACE=118
|
||||||
LBRACK=119
|
RBRACE=119
|
||||||
RBRACK=120
|
LBRACK=120
|
||||||
LPAREN=121
|
RBRACK=121
|
||||||
RPAREN=122
|
LPAREN=122
|
||||||
LT=123
|
RPAREN=123
|
||||||
GT=124
|
LT=124
|
||||||
AMP=125
|
GT=125
|
||||||
EQUAL=126
|
AMP=126
|
||||||
INTEGER=127
|
EQUAL=127
|
||||||
JSON_NUMBER=128
|
INTEGER=128
|
||||||
IDENTIFIER=129
|
JSON_NUMBER=129
|
||||||
STRING_LITERAL=130
|
IDENTIFIER=130
|
||||||
LINE_COMMENT=131
|
STRING_LITERAL=131
|
||||||
BLOCK_COMMENT=132
|
LINE_COMMENT=132
|
||||||
WS=133
|
BLOCK_COMMENT=133
|
||||||
|
WS=134
|
||||||
'workspace'=1
|
'workspace'=1
|
||||||
'result-bytes'=2
|
'result-bytes'=2
|
||||||
'rpc-calls'=3
|
'rpc-calls'=3
|
||||||
'deadline-ms'=4
|
'deadline-ms'=4
|
||||||
'query'=5
|
'query'=5
|
||||||
'specialize'=6
|
'reflection'=6
|
||||||
'root'=7
|
'specialize'=7
|
||||||
'document'=8
|
'root'=8
|
||||||
'fragments'=9
|
'document'=9
|
||||||
'view'=10
|
'fragments'=10
|
||||||
'max'=11
|
'view'=11
|
||||||
'allow'=12
|
'max'=12
|
||||||
'poll'=13
|
'allow'=13
|
||||||
'queryable'=14
|
'poll'=14
|
||||||
'rpc'=15
|
'queryable'=15
|
||||||
'query-reason'=16
|
'rpc'=16
|
||||||
'type'=17
|
'query-reason'=17
|
||||||
'object'=18
|
'type'=18
|
||||||
'storable'=19
|
'object'=19
|
||||||
'implements'=20
|
'storable'=20
|
||||||
'ref'=21
|
'implements'=21
|
||||||
'fragment'=22
|
'ref'=22
|
||||||
'import'=23
|
'fragment'=23
|
||||||
'external'=24
|
'import'=24
|
||||||
'atom'=25
|
'external'=25
|
||||||
'interface'=26
|
'atom'=26
|
||||||
'interfaces'=27
|
'interface'=27
|
||||||
'package'=28
|
'interfaces'=28
|
||||||
'value'=29
|
'package'=29
|
||||||
'relation'=30
|
'value'=30
|
||||||
'operation'=31
|
'relation'=31
|
||||||
'function'=32
|
'operation'=32
|
||||||
'constructor'=33
|
'function'=33
|
||||||
'constructs'=34
|
'constructor'=34
|
||||||
'input'=35
|
'constructs'=35
|
||||||
'conform'=36
|
'input'=36
|
||||||
'as'=37
|
'conform'=37
|
||||||
'bind'=38
|
'as'=38
|
||||||
'static'=39
|
'bind'=39
|
||||||
'to'=40
|
'static'=40
|
||||||
'private'=41
|
'to'=41
|
||||||
'shared'=42
|
'private'=42
|
||||||
'state'=43
|
'shared'=43
|
||||||
'edge'=44
|
'state'=44
|
||||||
'projection'=45
|
'edge'=45
|
||||||
'with'=46
|
'projection'=46
|
||||||
'using'=47
|
'with'=47
|
||||||
'via'=48
|
'using'=48
|
||||||
'materialize'=49
|
'via'=49
|
||||||
'if'=50
|
'materialize'=50
|
||||||
'absent'=51
|
'if'=51
|
||||||
'on'=52
|
'absent'=52
|
||||||
'policy'=53
|
'on'=53
|
||||||
'default'=54
|
'policy'=54
|
||||||
'source'=55
|
'default'=55
|
||||||
'repository'=56
|
'source'=56
|
||||||
'commit'=57
|
'repository'=57
|
||||||
'revision'=58
|
'commit'=58
|
||||||
'semantic-major'=59
|
'revision'=59
|
||||||
'on-delete'=60
|
'semantic-major'=60
|
||||||
'retain-other'=61
|
'on-delete'=61
|
||||||
'keyed'=62
|
'retain-other'=62
|
||||||
'public-traversal'=63
|
'keyed'=63
|
||||||
'id'=64
|
'public-traversal'=64
|
||||||
'doc'=65
|
'id'=65
|
||||||
'mode'=66
|
'doc'=66
|
||||||
'emits'=67
|
'mode'=67
|
||||||
'receiver'=68
|
'emits'=68
|
||||||
'requires'=69
|
'receiver'=69
|
||||||
'any'=70
|
'requires'=70
|
||||||
'get'=71
|
'any'=71
|
||||||
'set'=72
|
'get'=72
|
||||||
'watch'=73
|
'set'=73
|
||||||
'start'=74
|
'watch'=74
|
||||||
'stop'=75
|
'start'=75
|
||||||
'read'=76
|
'stop'=76
|
||||||
'write'=77
|
'read'=77
|
||||||
'resolve'=78
|
'write'=78
|
||||||
'connect'=79
|
'resolve'=79
|
||||||
'disconnect'=80
|
'connect'=80
|
||||||
'call'=81
|
'disconnect'=81
|
||||||
'watch-start'=82
|
'call'=82
|
||||||
'watch-stop'=83
|
'watch-start'=83
|
||||||
'subscribe'=84
|
'watch-stop'=84
|
||||||
'unsubscribe'=85
|
'subscribe'=85
|
||||||
'optimistic-register'=86
|
'unsubscribe'=86
|
||||||
'crdt'=87
|
'optimistic-register'=87
|
||||||
'optional-one'=88
|
'crdt'=88
|
||||||
'exactly-one'=89
|
'optional-one'=89
|
||||||
'many-unique'=90
|
'exactly-one'=90
|
||||||
'many'=91
|
'many-unique'=91
|
||||||
'ordered'=92
|
'many'=92
|
||||||
'unit'=93
|
'ordered'=93
|
||||||
'watch-handle'=94
|
'unit'=94
|
||||||
'message'=95
|
'watch-handle'=95
|
||||||
'atom-ref'=96
|
'message'=96
|
||||||
'interface-ref'=97
|
'atom-ref'=97
|
||||||
'optional'=98
|
'interface-ref'=98
|
||||||
'list'=99
|
'optional'=99
|
||||||
'record'=100
|
'list'=100
|
||||||
'bool'=101
|
'record'=101
|
||||||
'bytes'=102
|
'bool'=102
|
||||||
'double'=103
|
'bytes'=103
|
||||||
'int32'=104
|
'double'=104
|
||||||
'int64'=105
|
'int32'=105
|
||||||
'string'=106
|
'int64'=106
|
||||||
'uint32'=107
|
'string'=107
|
||||||
'uint64'=108
|
'uint32'=108
|
||||||
'true'=109
|
'uint64'=109
|
||||||
'false'=110
|
'true'=110
|
||||||
'null'=111
|
'false'=111
|
||||||
'->'=112
|
'null'=112
|
||||||
':'=113
|
'->'=113
|
||||||
';'=114
|
':'=114
|
||||||
','=115
|
';'=115
|
||||||
'.'=116
|
','=116
|
||||||
'{'=117
|
'.'=117
|
||||||
'}'=118
|
'{'=118
|
||||||
'['=119
|
'}'=119
|
||||||
']'=120
|
'['=120
|
||||||
'('=121
|
']'=121
|
||||||
')'=122
|
'('=122
|
||||||
'<'=123
|
')'=123
|
||||||
'>'=124
|
'<'=124
|
||||||
'&'=125
|
'>'=125
|
||||||
'='=126
|
'&'=126
|
||||||
|
'='=127
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,257 +3,259 @@ RESULT_BYTES=2
|
|||||||
RPC_CALLS=3
|
RPC_CALLS=3
|
||||||
DEADLINE_MS=4
|
DEADLINE_MS=4
|
||||||
QUERY=5
|
QUERY=5
|
||||||
SPECIALIZE=6
|
REFLECTION=6
|
||||||
ROOT=7
|
SPECIALIZE=7
|
||||||
DOCUMENT=8
|
ROOT=8
|
||||||
FRAGMENTS=9
|
DOCUMENT=9
|
||||||
VIEW=10
|
FRAGMENTS=10
|
||||||
MAX=11
|
VIEW=11
|
||||||
ALLOW=12
|
MAX=12
|
||||||
POLL=13
|
ALLOW=13
|
||||||
QUERYABLE=14
|
POLL=14
|
||||||
RPC=15
|
QUERYABLE=15
|
||||||
QUERY_REASON=16
|
RPC=16
|
||||||
TYPE=17
|
QUERY_REASON=17
|
||||||
OBJECT=18
|
TYPE=18
|
||||||
STORABLE=19
|
OBJECT=19
|
||||||
IMPLEMENTS=20
|
STORABLE=20
|
||||||
REF=21
|
IMPLEMENTS=21
|
||||||
FRAGMENT=22
|
REF=22
|
||||||
IMPORT=23
|
FRAGMENT=23
|
||||||
EXTERNAL=24
|
IMPORT=24
|
||||||
ATOM=25
|
EXTERNAL=25
|
||||||
INTERFACE=26
|
ATOM=26
|
||||||
INTERFACES=27
|
INTERFACE=27
|
||||||
PACKAGE=28
|
INTERFACES=28
|
||||||
VALUE=29
|
PACKAGE=29
|
||||||
RELATION=30
|
VALUE=30
|
||||||
OPERATION=31
|
RELATION=31
|
||||||
FUNCTION=32
|
OPERATION=32
|
||||||
CONSTRUCTOR=33
|
FUNCTION=33
|
||||||
CONSTRUCTS=34
|
CONSTRUCTOR=34
|
||||||
INPUT=35
|
CONSTRUCTS=35
|
||||||
CONFORM=36
|
INPUT=36
|
||||||
AS=37
|
CONFORM=37
|
||||||
BIND=38
|
AS=38
|
||||||
STATIC=39
|
BIND=39
|
||||||
TO=40
|
STATIC=40
|
||||||
PRIVATE=41
|
TO=41
|
||||||
SHARED=42
|
PRIVATE=42
|
||||||
STATE=43
|
SHARED=43
|
||||||
EDGE=44
|
STATE=44
|
||||||
PROJECTION=45
|
EDGE=45
|
||||||
WITH=46
|
PROJECTION=46
|
||||||
USING=47
|
WITH=47
|
||||||
VIA=48
|
USING=48
|
||||||
MATERIALIZE=49
|
VIA=49
|
||||||
IF=50
|
MATERIALIZE=50
|
||||||
ABSENT=51
|
IF=51
|
||||||
ON=52
|
ABSENT=52
|
||||||
POLICY=53
|
ON=53
|
||||||
DEFAULT=54
|
POLICY=54
|
||||||
SOURCE=55
|
DEFAULT=55
|
||||||
REPOSITORY=56
|
SOURCE=56
|
||||||
COMMIT=57
|
REPOSITORY=57
|
||||||
REVISION=58
|
COMMIT=58
|
||||||
SEMANTIC_MAJOR=59
|
REVISION=59
|
||||||
ON_DELETE=60
|
SEMANTIC_MAJOR=60
|
||||||
RETAIN_OTHER=61
|
ON_DELETE=61
|
||||||
KEYED=62
|
RETAIN_OTHER=62
|
||||||
PUBLIC_TRAVERSAL=63
|
KEYED=63
|
||||||
ID=64
|
PUBLIC_TRAVERSAL=64
|
||||||
DOC=65
|
ID=65
|
||||||
MODE=66
|
DOC=66
|
||||||
EMITS=67
|
MODE=67
|
||||||
RECEIVER=68
|
EMITS=68
|
||||||
REQUIRES=69
|
RECEIVER=69
|
||||||
ANY=70
|
REQUIRES=70
|
||||||
GET=71
|
ANY=71
|
||||||
SET=72
|
GET=72
|
||||||
WATCH=73
|
SET=73
|
||||||
START=74
|
WATCH=74
|
||||||
STOP=75
|
START=75
|
||||||
READ=76
|
STOP=76
|
||||||
WRITE=77
|
READ=77
|
||||||
RESOLVE=78
|
WRITE=78
|
||||||
CONNECT=79
|
RESOLVE=79
|
||||||
DISCONNECT=80
|
CONNECT=80
|
||||||
CALL=81
|
DISCONNECT=81
|
||||||
WATCH_START=82
|
CALL=82
|
||||||
WATCH_STOP=83
|
WATCH_START=83
|
||||||
SUBSCRIBE=84
|
WATCH_STOP=84
|
||||||
UNSUBSCRIBE=85
|
SUBSCRIBE=85
|
||||||
OPTIMISTIC_REGISTER=86
|
UNSUBSCRIBE=86
|
||||||
CRDT=87
|
OPTIMISTIC_REGISTER=87
|
||||||
OPTIONAL_ONE=88
|
CRDT=88
|
||||||
EXACTLY_ONE=89
|
OPTIONAL_ONE=89
|
||||||
MANY_UNIQUE=90
|
EXACTLY_ONE=90
|
||||||
MANY=91
|
MANY_UNIQUE=91
|
||||||
ORDERED=92
|
MANY=92
|
||||||
UNIT=93
|
ORDERED=93
|
||||||
WATCH_HANDLE=94
|
UNIT=94
|
||||||
MESSAGE=95
|
WATCH_HANDLE=95
|
||||||
ATOM_REF=96
|
MESSAGE=96
|
||||||
INTERFACE_REF=97
|
ATOM_REF=97
|
||||||
OPTIONAL=98
|
INTERFACE_REF=98
|
||||||
LIST=99
|
OPTIONAL=99
|
||||||
RECORD=100
|
LIST=100
|
||||||
BOOL=101
|
RECORD=101
|
||||||
BYTES=102
|
BOOL=102
|
||||||
DOUBLE=103
|
BYTES=103
|
||||||
INT32=104
|
DOUBLE=104
|
||||||
INT64=105
|
INT32=105
|
||||||
STRING=106
|
INT64=106
|
||||||
UINT32=107
|
STRING=107
|
||||||
UINT64=108
|
UINT32=108
|
||||||
TRUE=109
|
UINT64=109
|
||||||
FALSE=110
|
TRUE=110
|
||||||
NULL=111
|
FALSE=111
|
||||||
ARROW=112
|
NULL=112
|
||||||
COLON=113
|
ARROW=113
|
||||||
SEMI=114
|
COLON=114
|
||||||
COMMA=115
|
SEMI=115
|
||||||
DOT=116
|
COMMA=116
|
||||||
LBRACE=117
|
DOT=117
|
||||||
RBRACE=118
|
LBRACE=118
|
||||||
LBRACK=119
|
RBRACE=119
|
||||||
RBRACK=120
|
LBRACK=120
|
||||||
LPAREN=121
|
RBRACK=121
|
||||||
RPAREN=122
|
LPAREN=122
|
||||||
LT=123
|
RPAREN=123
|
||||||
GT=124
|
LT=124
|
||||||
AMP=125
|
GT=125
|
||||||
EQUAL=126
|
AMP=126
|
||||||
INTEGER=127
|
EQUAL=127
|
||||||
JSON_NUMBER=128
|
INTEGER=128
|
||||||
IDENTIFIER=129
|
JSON_NUMBER=129
|
||||||
STRING_LITERAL=130
|
IDENTIFIER=130
|
||||||
LINE_COMMENT=131
|
STRING_LITERAL=131
|
||||||
BLOCK_COMMENT=132
|
LINE_COMMENT=132
|
||||||
WS=133
|
BLOCK_COMMENT=133
|
||||||
|
WS=134
|
||||||
'workspace'=1
|
'workspace'=1
|
||||||
'result-bytes'=2
|
'result-bytes'=2
|
||||||
'rpc-calls'=3
|
'rpc-calls'=3
|
||||||
'deadline-ms'=4
|
'deadline-ms'=4
|
||||||
'query'=5
|
'query'=5
|
||||||
'specialize'=6
|
'reflection'=6
|
||||||
'root'=7
|
'specialize'=7
|
||||||
'document'=8
|
'root'=8
|
||||||
'fragments'=9
|
'document'=9
|
||||||
'view'=10
|
'fragments'=10
|
||||||
'max'=11
|
'view'=11
|
||||||
'allow'=12
|
'max'=12
|
||||||
'poll'=13
|
'allow'=13
|
||||||
'queryable'=14
|
'poll'=14
|
||||||
'rpc'=15
|
'queryable'=15
|
||||||
'query-reason'=16
|
'rpc'=16
|
||||||
'type'=17
|
'query-reason'=17
|
||||||
'object'=18
|
'type'=18
|
||||||
'storable'=19
|
'object'=19
|
||||||
'implements'=20
|
'storable'=20
|
||||||
'ref'=21
|
'implements'=21
|
||||||
'fragment'=22
|
'ref'=22
|
||||||
'import'=23
|
'fragment'=23
|
||||||
'external'=24
|
'import'=24
|
||||||
'atom'=25
|
'external'=25
|
||||||
'interface'=26
|
'atom'=26
|
||||||
'interfaces'=27
|
'interface'=27
|
||||||
'package'=28
|
'interfaces'=28
|
||||||
'value'=29
|
'package'=29
|
||||||
'relation'=30
|
'value'=30
|
||||||
'operation'=31
|
'relation'=31
|
||||||
'function'=32
|
'operation'=32
|
||||||
'constructor'=33
|
'function'=33
|
||||||
'constructs'=34
|
'constructor'=34
|
||||||
'input'=35
|
'constructs'=35
|
||||||
'conform'=36
|
'input'=36
|
||||||
'as'=37
|
'conform'=37
|
||||||
'bind'=38
|
'as'=38
|
||||||
'static'=39
|
'bind'=39
|
||||||
'to'=40
|
'static'=40
|
||||||
'private'=41
|
'to'=41
|
||||||
'shared'=42
|
'private'=42
|
||||||
'state'=43
|
'shared'=43
|
||||||
'edge'=44
|
'state'=44
|
||||||
'projection'=45
|
'edge'=45
|
||||||
'with'=46
|
'projection'=46
|
||||||
'using'=47
|
'with'=47
|
||||||
'via'=48
|
'using'=48
|
||||||
'materialize'=49
|
'via'=49
|
||||||
'if'=50
|
'materialize'=50
|
||||||
'absent'=51
|
'if'=51
|
||||||
'on'=52
|
'absent'=52
|
||||||
'policy'=53
|
'on'=53
|
||||||
'default'=54
|
'policy'=54
|
||||||
'source'=55
|
'default'=55
|
||||||
'repository'=56
|
'source'=56
|
||||||
'commit'=57
|
'repository'=57
|
||||||
'revision'=58
|
'commit'=58
|
||||||
'semantic-major'=59
|
'revision'=59
|
||||||
'on-delete'=60
|
'semantic-major'=60
|
||||||
'retain-other'=61
|
'on-delete'=61
|
||||||
'keyed'=62
|
'retain-other'=62
|
||||||
'public-traversal'=63
|
'keyed'=63
|
||||||
'id'=64
|
'public-traversal'=64
|
||||||
'doc'=65
|
'id'=65
|
||||||
'mode'=66
|
'doc'=66
|
||||||
'emits'=67
|
'mode'=67
|
||||||
'receiver'=68
|
'emits'=68
|
||||||
'requires'=69
|
'receiver'=69
|
||||||
'any'=70
|
'requires'=70
|
||||||
'get'=71
|
'any'=71
|
||||||
'set'=72
|
'get'=72
|
||||||
'watch'=73
|
'set'=73
|
||||||
'start'=74
|
'watch'=74
|
||||||
'stop'=75
|
'start'=75
|
||||||
'read'=76
|
'stop'=76
|
||||||
'write'=77
|
'read'=77
|
||||||
'resolve'=78
|
'write'=78
|
||||||
'connect'=79
|
'resolve'=79
|
||||||
'disconnect'=80
|
'connect'=80
|
||||||
'call'=81
|
'disconnect'=81
|
||||||
'watch-start'=82
|
'call'=82
|
||||||
'watch-stop'=83
|
'watch-start'=83
|
||||||
'subscribe'=84
|
'watch-stop'=84
|
||||||
'unsubscribe'=85
|
'subscribe'=85
|
||||||
'optimistic-register'=86
|
'unsubscribe'=86
|
||||||
'crdt'=87
|
'optimistic-register'=87
|
||||||
'optional-one'=88
|
'crdt'=88
|
||||||
'exactly-one'=89
|
'optional-one'=89
|
||||||
'many-unique'=90
|
'exactly-one'=90
|
||||||
'many'=91
|
'many-unique'=91
|
||||||
'ordered'=92
|
'many'=92
|
||||||
'unit'=93
|
'ordered'=93
|
||||||
'watch-handle'=94
|
'unit'=94
|
||||||
'message'=95
|
'watch-handle'=95
|
||||||
'atom-ref'=96
|
'message'=96
|
||||||
'interface-ref'=97
|
'atom-ref'=97
|
||||||
'optional'=98
|
'interface-ref'=98
|
||||||
'list'=99
|
'optional'=99
|
||||||
'record'=100
|
'list'=100
|
||||||
'bool'=101
|
'record'=101
|
||||||
'bytes'=102
|
'bool'=102
|
||||||
'double'=103
|
'bytes'=103
|
||||||
'int32'=104
|
'double'=104
|
||||||
'int64'=105
|
'int32'=105
|
||||||
'string'=106
|
'int64'=106
|
||||||
'uint32'=107
|
'string'=107
|
||||||
'uint64'=108
|
'uint32'=108
|
||||||
'true'=109
|
'uint64'=109
|
||||||
'false'=110
|
'true'=110
|
||||||
'null'=111
|
'false'=111
|
||||||
'->'=112
|
'null'=112
|
||||||
':'=113
|
'->'=113
|
||||||
';'=114
|
':'=114
|
||||||
','=115
|
';'=115
|
||||||
'.'=116
|
','=116
|
||||||
'{'=117
|
'.'=117
|
||||||
'}'=118
|
'{'=118
|
||||||
'['=119
|
'}'=119
|
||||||
']'=120
|
'['=120
|
||||||
'('=121
|
']'=121
|
||||||
')'=122
|
'('=122
|
||||||
'<'=123
|
')'=123
|
||||||
'>'=124
|
'<'=124
|
||||||
'&'=125
|
'>'=125
|
||||||
'='=126
|
'&'=126
|
||||||
|
'='=127
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -849,6 +849,12 @@ const lowerQueryReference = (
|
|||||||
const lowerDependencyPort = (state: LoweringState, context: DependencyPortContext): DependencyPort | undefined => {
|
const lowerDependencyPort = (state: LoweringState, context: DependencyPortContext): DependencyPort | undefined => {
|
||||||
const name = identifier(context.identifier(0));
|
const name = identifier(context.identifier(0));
|
||||||
const id = capabilityId.dependencyPort(stringValue(context.stringLiteral()));
|
const id = capabilityId.dependencyPort(stringValue(context.stringLiteral()));
|
||||||
|
if (context.REFLECTION())
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
displayName: name,
|
||||||
|
requirement: { kind: "reflection", selectors: context.identifierList()!.identifier().map(identifier) },
|
||||||
|
};
|
||||||
if (context.QUERY()) {
|
if (context.QUERY()) {
|
||||||
const query = lowerQueryReference(
|
const query = lowerQueryReference(
|
||||||
state,
|
state,
|
||||||
@@ -1097,6 +1103,11 @@ const lowerGenericPackageExport = (
|
|||||||
.primitiveList()
|
.primitiveList()
|
||||||
?.primitive()
|
?.primitive()
|
||||||
.map((item) => text(item)) ?? [];
|
.map((item) => text(item)) ?? [];
|
||||||
|
if (port.REFLECTION())
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
requirement: { kind: "reflection", selectors: port.identifierList()!.identifier().map(identifier) },
|
||||||
|
};
|
||||||
if (port.QUERY()) {
|
if (port.QUERY()) {
|
||||||
const query = lowerQueryReference(state, identifier(port.identifier(1)), identifier(port.identifier(2)), port);
|
const query = lowerQueryReference(state, identifier(port.identifier(1)), identifier(port.identifier(2)), port);
|
||||||
if (!query)
|
if (!query)
|
||||||
@@ -1575,6 +1586,10 @@ const lowerBoundDependencies = (
|
|||||||
);
|
);
|
||||||
return projectionId ? { edgeTypeId: attachment.attachment.id, projectionId } : undefined;
|
return projectionId ? { edgeTypeId: attachment.attachment.id, projectionId } : undefined;
|
||||||
};
|
};
|
||||||
|
if (entry.REFLECTION())
|
||||||
|
return [
|
||||||
|
{ portId, binding: { kind: "reflection", selectors: entry.identifierList()!.identifier().map(identifier) } },
|
||||||
|
];
|
||||||
if (entry.QUERY()) {
|
if (entry.QUERY()) {
|
||||||
const query = lowerQueryReference(state, identifier(entry.identifier(1)), identifier(entry.identifier(2)), entry);
|
const query = lowerQueryReference(state, identifier(entry.identifier(1)), identifier(entry.identifier(2)), entry);
|
||||||
const via = entry.VIA() ? traversal(identifier(entry.identifier(3)), identifier(entry.identifier(4))) : undefined;
|
const via = entry.VIA() ? traversal(identifier(entry.identifier(3)), identifier(entry.identifier(4))) : undefined;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
|
|
||||||
export type GenericDependencyPort = Omit<DependencyPort, "requirement"> & {
|
export type GenericDependencyPort = Omit<DependencyPort, "requirement"> & {
|
||||||
requirement:
|
requirement:
|
||||||
| Extract<DependencyPort["requirement"], { kind: "query" }>
|
| Extract<DependencyPort["requirement"], { kind: "query" | "reflection" }>
|
||||||
| {
|
| {
|
||||||
kind: "state";
|
kind: "state";
|
||||||
valueType: ValueTypeExpression;
|
valueType: ValueTypeExpression;
|
||||||
@@ -80,6 +80,7 @@ export const specializePackageExport = (
|
|||||||
const ports: DependencyPort[] = definition.dependencyPorts.map((port) => {
|
const ports: DependencyPort[] = definition.dependencyPorts.map((port) => {
|
||||||
const requirement = port.requirement;
|
const requirement = port.requirement;
|
||||||
switch (requirement.kind) {
|
switch (requirement.kind) {
|
||||||
|
case "reflection":
|
||||||
case "query":
|
case "query":
|
||||||
return { ...port, requirement };
|
return { ...port, requirement };
|
||||||
case "state":
|
case "state":
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ export type PackageReceiverRequirement =
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type DependencyPortRequirement =
|
export type DependencyPortRequirement =
|
||||||
|
| { kind: "reflection"; selectors: string[] }
|
||||||
| { kind: "query"; packageRevisionId: PackageRevisionId; queryId: string }
|
| { kind: "query"; packageRevisionId: PackageRevisionId; queryId: string }
|
||||||
| {
|
| {
|
||||||
kind: "state";
|
kind: "state";
|
||||||
@@ -292,6 +293,7 @@ export interface PackageRevision {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type DependencyBinding =
|
export type DependencyBinding =
|
||||||
|
| { kind: "reflection"; selectors: string[]; via?: never }
|
||||||
| {
|
| {
|
||||||
kind: "query";
|
kind: "query";
|
||||||
packageRevisionId: PackageRevisionId;
|
packageRevisionId: PackageRevisionId;
|
||||||
|
|||||||
@@ -998,6 +998,16 @@ const validatePackages = (
|
|||||||
for (const [portIndex, port] of entry.dependencyPorts.entries()) {
|
for (const [portIndex, port] of entry.dependencyPorts.entries()) {
|
||||||
const portPath = `${exportPath}.dependencyPorts[${portIndex}]`;
|
const portPath = `${exportPath}.dependencyPorts[${portIndex}]`;
|
||||||
switch (port.requirement.kind) {
|
switch (port.requirement.kind) {
|
||||||
|
case "reflection":
|
||||||
|
if (
|
||||||
|
!port.requirement.selectors.length ||
|
||||||
|
new Set(port.requirement.selectors).size !== port.requirement.selectors.length ||
|
||||||
|
port.requirement.selectors.some(
|
||||||
|
(kind) => !["active", "atoms", "interfaces", "conformances", "queries", "indexes"].includes(kind),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
issue(issues, "invalid-dependency-binding", portPath, "Reflection requires distinct supported selectors");
|
||||||
|
break;
|
||||||
case "query":
|
case "query":
|
||||||
if (
|
if (
|
||||||
!indexes.packages
|
!indexes.packages
|
||||||
@@ -1162,6 +1172,20 @@ const validateBoundDependencies = (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (requirement.kind) {
|
switch (requirement.kind) {
|
||||||
|
case "reflection": {
|
||||||
|
const selected = binding as Extract<DependencyBinding, { kind: "reflection" }>;
|
||||||
|
if (
|
||||||
|
selected.via ||
|
||||||
|
JSON.stringify([...selected.selectors].sort()) !== JSON.stringify([...requirement.selectors].sort())
|
||||||
|
)
|
||||||
|
issue(
|
||||||
|
issues,
|
||||||
|
"invalid-dependency-binding",
|
||||||
|
path,
|
||||||
|
"Reflection requires an explicit workspace binding with exactly the declared selectors",
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "query": {
|
case "query": {
|
||||||
const selected = binding as Extract<DependencyBinding, { kind: "query" }>;
|
const selected = binding as Extract<DependencyBinding, { kind: "query" }>;
|
||||||
const query = params.indexes.packages
|
const query = params.indexes.packages
|
||||||
|
|||||||
+451
-30
File diff suppressed because one or more lines are too long
@@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf";
|
|||||||
* Describes the file quixos/refs.proto.
|
* Describes the file quixos/refs.proto.
|
||||||
*/
|
*/
|
||||||
export const file_quixos_refs: GenFile = /*@__PURE__*/
|
export const file_quixos_refs: GenFile = /*@__PURE__*/
|
||||||
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInUKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCRIvCgtjb25mb3JtYW5jZRgDIAEoCzIaLnF1aXhvcy5Db25mb3JtYW5jZVdpdG5lc3Mi0QEKDEZpZWxkRWRpdGluZxIbChNnZXR0ZXJfb3BlcmF0aW9uX2lkGAEgASgJEhsKE3NldHRlcl9vcGVyYXRpb25faWQYAiABKAkSFQoNZG9jdW1lbnRfdHlwZRgDIAEoCRIWCg5iaW5kaW5nX2RpZ2VzdBgEIAEoCRInCgRtb2RlGAUgASgOMhkucXVpeG9zLkZpZWxkRWRpdGluZy5Nb2RlIi8KBE1vZGUSDwoLVU5TUEVDSUZJRUQQABIMCghSRUdJU1RFUhABEggKBENSRFQQAiKWAQoSQ29uZm9ybWFuY2VXaXRuZXNzEhEKCW9iamVjdF9pZBgBIAEoCRIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYAiABKAkSFgoOY29uZm9ybWFuY2VfaWQYAyABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAQgASgJEhcKD3dvcmtzcGFjZV9lcG9jaBgFIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIpUCChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEh8KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABISCghxdWVyeV9pZBgHIAEoCUgAEjsKD3dvcmtzcGFjZV9xdWVyeRgIIAEoCzIgLnF1aXhvcy5Xb3Jrc3BhY2VRdWVyeURlcGVuZGVuY3lIABIRCglvYmplY3RfaWQYBiABKAlCCQoHYmluZGluZyKaAQoTV29ya3NwYWNlUXVlcnlTY29wZRIUCgx3b3Jrc3BhY2VfaWQYASABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAIgASgJEhcKD3dvcmtzcGFjZV9lcG9jaBgDIAEoCRIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYBCABKAkSFgoOYmluZGluZ19kaWdlc3QYBSABKAkiWAoYV29ya3NwYWNlUXVlcnlEZXBlbmRlbmN5EhAKCHF1ZXJ5X2lkGAEgASgJEioKBXNjb3BlGAIgASgLMhsucXVpeG9zLldvcmtzcGFjZVF1ZXJ5U2NvcGUiPQoORWRnZURlcGVuZGVuY3kSFAoMZWRnZV90eXBlX2lkGAEgASgJEhUKDXByb2plY3Rpb25faWQYAiABKAliBnByb3RvMw");
|
fileDesc("ChFxdWl4b3MvcmVmcy5wcm90bxIGcXVpeG9zInUKDUNhcGFiaWxpdHlSZWYSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhQKDG9wZXJhdGlvbl9pZBgCIAEoCRIvCgtjb25mb3JtYW5jZRgDIAEoCzIaLnF1aXhvcy5Db25mb3JtYW5jZVdpdG5lc3Mi0QEKDEZpZWxkRWRpdGluZxIbChNnZXR0ZXJfb3BlcmF0aW9uX2lkGAEgASgJEhsKE3NldHRlcl9vcGVyYXRpb25faWQYAiABKAkSFQoNZG9jdW1lbnRfdHlwZRgDIAEoCRIWCg5iaW5kaW5nX2RpZ2VzdBgEIAEoCRInCgRtb2RlGAUgASgOMhkucXVpeG9zLkZpZWxkRWRpdGluZy5Nb2RlIi8KBE1vZGUSDwoLVU5TUEVDSUZJRUQQABIMCghSRUdJU1RFUhABEggKBENSRFQQAiKWAQoSQ29uZm9ybWFuY2VXaXRuZXNzEhEKCW9iamVjdF9pZBgBIAEoCRIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYAiABKAkSFgoOY29uZm9ybWFuY2VfaWQYAyABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAQgASgJEhcKD3dvcmtzcGFjZV9lcG9jaBgFIAEoCSJCChBQYWNrYWdlRXhwb3J0UmVmEhsKE3BhY2thZ2VfcmV2aXNpb25faWQYASABKAkSEQoJZXhwb3J0X2lkGAIgASgJIskCChJJbmplY3RlZERlcGVuZGVuY3kSDwoHcG9ydF9pZBgBIAEoCRIXCg1zdGF0ZV9zbG90X2lkGAIgASgJSAASJgoEZWRnZRgDIAEoCzIWLnF1aXhvcy5FZGdlRGVwZW5kZW5jeUgAEh8KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgEIAEoCUgAEh0KE2NvbnN0cnVjdG9yX2F0b21faWQYBSABKAlIABISCghxdWVyeV9pZBgHIAEoCUgAEjsKD3dvcmtzcGFjZV9xdWVyeRgIIAEoCzIgLnF1aXhvcy5Xb3Jrc3BhY2VRdWVyeURlcGVuZGVuY3lIABIyCgpyZWZsZWN0aW9uGAkgASgLMhwucXVpeG9zLlJlZmxlY3Rpb25EZXBlbmRlbmN5SAASEQoJb2JqZWN0X2lkGAYgASgJQgkKB2JpbmRpbmciWAoUUmVmbGVjdGlvbkRlcGVuZGVuY3kSFAoMd29ya3NwYWNlX2lkGAEgASgJEhcKD3dvcmtzcGFjZV9lcG9jaBgCIAEoCRIRCglzZWxlY3RvcnMYAyADKAkimgEKE1dvcmtzcGFjZVF1ZXJ5U2NvcGUSFAoMd29ya3NwYWNlX2lkGAEgASgJEh0KFXdvcmtzcGFjZV9yZXZpc2lvbl9pZBgCIAEoCRIXCg93b3Jrc3BhY2VfZXBvY2gYAyABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAQgASgJEhYKDmJpbmRpbmdfZGlnZXN0GAUgASgJIlgKGFdvcmtzcGFjZVF1ZXJ5RGVwZW5kZW5jeRIQCghxdWVyeV9pZBgBIAEoCRIqCgVzY29wZRgCIAEoCzIbLnF1aXhvcy5Xb3Jrc3BhY2VRdWVyeVNjb3BlIj0KDkVkZ2VEZXBlbmRlbmN5EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAIgASgJYgZwcm90bzM");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.CapabilityRef
|
* @generated from message quixos.CapabilityRef
|
||||||
@@ -213,6 +213,12 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
|
|||||||
*/
|
*/
|
||||||
value: WorkspaceQueryDependency;
|
value: WorkspaceQueryDependency;
|
||||||
case: "workspaceQuery";
|
case: "workspaceQuery";
|
||||||
|
} | {
|
||||||
|
/**
|
||||||
|
* @generated from field: quixos.ReflectionDependency reflection = 9;
|
||||||
|
*/
|
||||||
|
value: ReflectionDependency;
|
||||||
|
case: "reflection";
|
||||||
} | { case: undefined; value?: undefined };
|
} | { case: undefined; value?: undefined };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,6 +237,33 @@ export type InjectedDependency = Message<"quixos.InjectedDependency"> & {
|
|||||||
export const InjectedDependencySchema: GenMessage<InjectedDependency> = /*@__PURE__*/
|
export const InjectedDependencySchema: GenMessage<InjectedDependency> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 4);
|
messageDesc(file_quixos_refs, 4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from message quixos.ReflectionDependency
|
||||||
|
*/
|
||||||
|
export type ReflectionDependency = Message<"quixos.ReflectionDependency"> & {
|
||||||
|
/**
|
||||||
|
* @generated from field: string workspace_id = 1;
|
||||||
|
*/
|
||||||
|
workspaceId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: string workspace_epoch = 2;
|
||||||
|
*/
|
||||||
|
workspaceEpoch: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @generated from field: repeated string selectors = 3;
|
||||||
|
*/
|
||||||
|
selectors: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the message quixos.ReflectionDependency.
|
||||||
|
* Use `create(ReflectionDependencySchema)` to create a new message.
|
||||||
|
*/
|
||||||
|
export const ReflectionDependencySchema: GenMessage<ReflectionDependency> = /*@__PURE__*/
|
||||||
|
messageDesc(file_quixos_refs, 5);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scope evidence is not authority by itself. The caller must also hold the
|
* Scope evidence is not authority by itself. The caller must also hold the
|
||||||
* matching workspace-query grant (or the authenticated workspace user grant).
|
* matching workspace-query grant (or the authenticated workspace user grant).
|
||||||
@@ -269,7 +302,7 @@ export type WorkspaceQueryScope = Message<"quixos.WorkspaceQueryScope"> & {
|
|||||||
* Use `create(WorkspaceQueryScopeSchema)` to create a new message.
|
* Use `create(WorkspaceQueryScopeSchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const WorkspaceQueryScopeSchema: GenMessage<WorkspaceQueryScope> = /*@__PURE__*/
|
export const WorkspaceQueryScopeSchema: GenMessage<WorkspaceQueryScope> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 5);
|
messageDesc(file_quixos_refs, 6);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.WorkspaceQueryDependency
|
* @generated from message quixos.WorkspaceQueryDependency
|
||||||
@@ -291,7 +324,7 @@ export type WorkspaceQueryDependency = Message<"quixos.WorkspaceQueryDependency"
|
|||||||
* Use `create(WorkspaceQueryDependencySchema)` to create a new message.
|
* Use `create(WorkspaceQueryDependencySchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const WorkspaceQueryDependencySchema: GenMessage<WorkspaceQueryDependency> = /*@__PURE__*/
|
export const WorkspaceQueryDependencySchema: GenMessage<WorkspaceQueryDependency> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 6);
|
messageDesc(file_quixos_refs, 7);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @generated from message quixos.EdgeDependency
|
* @generated from message quixos.EdgeDependency
|
||||||
@@ -313,5 +346,5 @@ export type EdgeDependency = Message<"quixos.EdgeDependency"> & {
|
|||||||
* Use `create(EdgeDependencySchema)` to create a new message.
|
* Use `create(EdgeDependencySchema)` to create a new message.
|
||||||
*/
|
*/
|
||||||
export const EdgeDependencySchema: GenMessage<EdgeDependency> = /*@__PURE__*/
|
export const EdgeDependencySchema: GenMessage<EdgeDependency> = /*@__PURE__*/
|
||||||
messageDesc(file_quixos_refs, 7);
|
messageDesc(file_quixos_refs, 8);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,17 @@ const schemaFor = (body: string): BindingSchema => {
|
|||||||
if (!compiled.ok || compiled.resource.kind !== "package") throw new Error("expected package");
|
if (!compiled.ok || compiled.resource.kind !== "package") throw new Error("expected package");
|
||||||
return { format: "quixos-bindings", version: 1, interfaces: [], packages: [compiled.resource.revision] };
|
return { format: "quixos-bindings", version: 1, interfaces: [], packages: [compiled.resource.revision] };
|
||||||
};
|
};
|
||||||
|
test("reflection ports generate explicit selector-restricted package bindings", () => {
|
||||||
|
const schema = schemaFor(
|
||||||
|
'function inspect id "inspect" : unit -> unit requires { reflection meta id "meta" [active, atoms, interfaces, conformances, queries, indexes]; };',
|
||||||
|
);
|
||||||
|
const generated = generateTypeScriptBindings(schema, "demo@1");
|
||||||
|
assert.match(
|
||||||
|
generated,
|
||||||
|
/QxReflectionPort<"active" \| "atoms" \| "interfaces" \| "conformances" \| "queries" \| "indexes">/,
|
||||||
|
);
|
||||||
|
assert.match(generated, /"kind": "reflection"/);
|
||||||
|
});
|
||||||
test("generator uses exact IDs, restricted ports, nominal references, and lossless scalar types", () => {
|
test("generator uses exact IDs, restricted ports, nominal references, and lossless scalar types", () => {
|
||||||
const schema = schemaFor(
|
const schema = schemaFor(
|
||||||
'operation run id "run-id" : list<int64> -> optional<atom-ref<Thing>> mode call receiver atom Thing requires { state payload id "payload-id" : bytes [read]; };',
|
'operation run id "run-id" : list<int64> -> optional<atom-ref<Thing>> mode call receiver atom Thing requires { state payload id "payload-id" : bytes [read]; };',
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ test("runtime conformance descriptors preserve closed and universal collection i
|
|||||||
};
|
};
|
||||||
operation inspect<object Item> id "inspect" : ref<Item> -> unit mode call receiver any requires {
|
operation inspect<object Item> id "inspect" : ref<Item> -> unit mode call receiver any requires {
|
||||||
interface items id "items" : Collection<Item>;
|
interface items id "items" : Collection<Item>;
|
||||||
|
reflection metadata id "metadata" [atoms, interfaces];
|
||||||
};
|
};
|
||||||
}`,
|
}`,
|
||||||
{ source, environment: { interfaces: new Map([["Collection", collection.resource.revision]]) } },
|
{ source, environment: { interfaces: new Map([["Collection", collection.resource.revision]]) } },
|
||||||
@@ -77,6 +78,11 @@ test("runtime conformance descriptors preserve closed and universal collection i
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
inspect: async (context) => {
|
inspect: async (context) => {
|
||||||
|
await context.ports.metadata.read({selector:{kind:"atoms",interfaceRevisionId:"named"}});
|
||||||
|
// @ts-expect-error Queries are outside this port's declared authority.
|
||||||
|
await context.ports.metadata.read({selector:{kind:"queries"}});
|
||||||
|
// @ts-expect-error Interface inventory does not support atom filters.
|
||||||
|
await context.ports.metadata.read({selector:{kind:"interfaces",atomId:"book"}});
|
||||||
const view = await context.conform.tryConform(context.objectId, context.ports.items.contract);
|
const view = await context.conform.tryConform(context.objectId, context.ports.items.contract);
|
||||||
if (view) await view["items.connect"](context.input);
|
if (view) await view["items.connect"](context.input);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import test from "node:test";
|
||||||
|
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
||||||
|
import { generateTypeScriptBindings } from "../src/bindings/index.js";
|
||||||
|
const source = { repository: "https://example.test/meta.git", commit: "a".repeat(40) };
|
||||||
|
|
||||||
|
test("reflection authority is an explicit checked workspace binding, including generic exports", () => {
|
||||||
|
const iface = compileCapabilityResourceSource(
|
||||||
|
'interface Inspect id "inspect" revision "inspect@1" {operation run id "run" : unit -> unit {call id "call";}}',
|
||||||
|
{ source },
|
||||||
|
);
|
||||||
|
assert.ok(iface.ok && iface.resource.kind === "interface");
|
||||||
|
if (!iface.ok || iface.resource.kind !== "interface") throw Error("interface");
|
||||||
|
const interfaceRevision = iface.resource.revision;
|
||||||
|
for (const generic of [false, true]) {
|
||||||
|
const pkg = compileCapabilityResourceSource(
|
||||||
|
`package Inspector id "inspector" revision "inspector@1" {operation run${generic ? "<value T>" : ""} id "run" : unit -> unit mode call receiver any requires {reflection meta id "meta" [atoms, interfaces];};}`,
|
||||||
|
{ source },
|
||||||
|
);
|
||||||
|
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
|
||||||
|
if (!pkg.ok || pkg.resource.kind !== "package") throw Error("package");
|
||||||
|
const packageRevision = pkg.resource.revision;
|
||||||
|
const compile = (selectors: string) =>
|
||||||
|
compileCapabilitySource(
|
||||||
|
`workspace W id "ws" revision "ws@1" commit "${source.commit}" {
|
||||||
|
import interface Inspect;import package Inspector;atom Thing id "thing";
|
||||||
|
conform Thing as Inspect id "inspection" {bind run.call to package Inspector.run${generic ? "<string>" : ""} with {meta to workspace reflection [${selectors}];};}
|
||||||
|
}`,
|
||||||
|
"workspace.qx",
|
||||||
|
{ interfaces: new Map([["Inspect", interfaceRevision]]), packages: new Map([["Inspector", packageRevision]]) },
|
||||||
|
);
|
||||||
|
const result = compile("atoms, interfaces");
|
||||||
|
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
||||||
|
assert.equal(compile("atoms").ok, false, "binding cannot narrow or expand the declared contract silently");
|
||||||
|
assert.equal(compile("atoms, interfaces, queries").ok, false);
|
||||||
|
if (!result.ok) throw Error("workspace");
|
||||||
|
const generated = generateTypeScriptBindings(
|
||||||
|
{
|
||||||
|
format: "quixos-bindings",
|
||||||
|
version: 1,
|
||||||
|
interfaces: result.workspace.interfaceImports,
|
||||||
|
packages: result.workspace.packageImports,
|
||||||
|
},
|
||||||
|
"inspector@1",
|
||||||
|
);
|
||||||
|
assert.match(generated, /QxReflectionPort/);
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user