@githolon/dsl 0.58.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dart/CHANGELOG.md +7 -0
- package/dart/lib/nomos_client.dart +6 -14
- package/dart/lib/src/provider.dart +1 -1
- package/dart/lib/src/webview_bridge.dart +7 -181
- package/dart/lib/testing.dart +13 -0
- package/dart/pubspec.lock +7 -0
- package/dart/pubspec.yaml +5 -1
- package/dart/pubspec_overrides.yaml +7 -0
- package/dart_types/CHANGELOG.md +6 -0
- package/dart_types/lib/nomos_types.dart +29 -0
- package/dart_types/lib/src/error_info.dart +184 -0
- package/{dart → dart_types}/lib/src/errors.dart +1 -1
- package/dart_types/pubspec.lock +421 -0
- package/dart_types/pubspec.yaml +23 -0
- package/package.json +4 -1
- package/src/codegen_dart.ts +1 -1
- package/src/codegen_dart_client.ts +14 -4
- package/src/codegen_proof.ts +15 -0
- package/src/compile_package_main.ts +531 -110
- package/src/law_check.ts +6 -0
- /package/{dart → dart_types}/lib/src/aggregate_meta.dart +0 -0
- /package/{dart → dart_types}/lib/src/driver.dart +0 -0
- /package/{dart → dart_types}/lib/src/null_slot.dart +0 -0
- /package/{dart → dart_types}/lib/src/offer.dart +0 -0
- /package/{dart → dart_types}/lib/src/schema_validation.dart +0 -0
- /package/{dart → dart_types}/lib/src/subscriptions.dart +0 -0
- /package/{dart → dart_types}/lib/src/wire.dart +0 -0
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## 0.38.0
|
|
2
|
+
- SPLIT: the pure data core (wire types, offer codec, NomosReads, aggregate meta, schema validation, error info) moved to the new `nomos_types` package; `nomos_client` depends on and re-exports it, so existing imports are unchanged. Frontend/UI code can now depend on `nomos_types` alone.
|
|
3
|
+
|
|
4
|
+
## 0.37.1
|
|
5
|
+
|
|
6
|
+
- Doc fix: `NomosBridge.attestedRead` docs now match the runtime — the call answers `{ entry: {queryId, result, attestation: …} }`; pass `result['entry']` as one `offerDirective` `attestations` element.
|
|
7
|
+
|
|
1
8
|
## 0.32.0
|
|
2
9
|
|
|
3
10
|
- SPATIAL READS: `NomosBbox` + `NomosBridge.spatialWithin(spatialId, bbox)` + `watchSpatial(...)` — the R*Tree probe surfaces on the bridge; generated clients (tooling ≥0.46) emit typed `sitesByBounds({required NomosBbox bbox})` + watch accessors.
|
|
@@ -23,25 +23,17 @@
|
|
|
23
23
|
/// which re-exports this framework barrel PLUS every generated domain.
|
|
24
24
|
library;
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
export '
|
|
26
|
+
// THE PURE-DATA CORE — the hand-written kernel wire types, the `offer(intent)` codec,
|
|
27
|
+
// the tri-state `NomosSlot<T>`, `NomosReads`, schema validation, runtime aggregate
|
|
28
|
+
// metadata, the data-only error/trace types, and the typed diagnostics moved to the
|
|
29
|
+
// standalone `nomos_types` package (so generated per-domain TYPES files resolve against
|
|
30
|
+
// it alone). Re-exported here so this barrel's public API is unchanged for consumers.
|
|
31
|
+
export 'package:nomos_types/nomos_types.dart';
|
|
32
32
|
// homeNameOf(subject) — the canonical home-workspace name (parity with @githolon/client + the law side).
|
|
33
33
|
export 'src/home.dart';
|
|
34
|
-
export 'src/subscriptions.dart';
|
|
35
|
-
export 'src/schema_validation.dart';
|
|
36
|
-
// RUNTIME AGGREGATE METADATA — the generated per-domain registry's support types
|
|
37
|
-
// (lookup by aggregateType for generic surfaces: history UIs, op renderers, agents).
|
|
38
|
-
export 'src/aggregate_meta.dart';
|
|
39
34
|
// THE WEBVIEW BRIDGE (app-binding boundary) — the async Dart runtime that drives the REAL githolon running
|
|
40
35
|
// in a WebView, so the generated typed client never needs a `MemoryPersistence` fake.
|
|
41
36
|
export 'src/webview_bridge.dart';
|
|
42
|
-
// TYPED DIAGNOSTICS (co2 feedback req 7) — the fixed set of ways the home-birth ceremony can fail, each
|
|
43
|
-
// extending NomosBridgeError so existing handlers still catch them, named so the app can branch on `is`.
|
|
44
|
-
export 'src/errors.dart';
|
|
45
37
|
// The PROVIDER boundary (server-side capability-provider SDK runtime: TaskOutcome /
|
|
46
38
|
// TaskSuccess / TaskFailure / TaskResult / TaskProvider / HostClock). The symmetric twin
|
|
47
39
|
// of `offer.dart`; the generated per-task provider classes build on it.
|
|
@@ -31,7 +31,7 @@ library;
|
|
|
31
31
|
|
|
32
32
|
import 'dart:convert';
|
|
33
33
|
|
|
34
|
-
import '
|
|
34
|
+
import 'package:nomos_types/nomos_types.dart' show NomosIntent;
|
|
35
35
|
|
|
36
36
|
/// The typed OUTCOME a provider handler returns for one Obligation: success, failure, blocked,
|
|
37
37
|
/// or dead-lettered.
|
|
@@ -18,7 +18,8 @@ import 'dart:async';
|
|
|
18
18
|
import 'dart:convert';
|
|
19
19
|
import 'dart:math';
|
|
20
20
|
|
|
21
|
-
import '
|
|
21
|
+
import 'package:nomos_types/nomos_types.dart'
|
|
22
|
+
show nomosErrorFromInfo, NomosTraceContext, NomosErrorInfo;
|
|
22
23
|
|
|
23
24
|
/// The protocol version the runner and the bridge agree on (`webview-runner.mjs` `WEBVIEW_BRIDGE_VERSION`).
|
|
24
25
|
const int kWebviewBridgeVersion = 1;
|
|
@@ -31,180 +32,6 @@ abstract interface class BridgeTransport {
|
|
|
31
32
|
Stream<Map<String, Object?>> get messages;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
/// Trace/span context carried over the bridge as plain JSON. It is intentionally OpenTelemetry-shaped without
|
|
35
|
-
/// importing an OTel SDK: apps can map it to spans later, while Nomos stays dependency-light at the runtime edge.
|
|
36
|
-
class NomosTraceContext {
|
|
37
|
-
final String? traceId;
|
|
38
|
-
final String? spanId;
|
|
39
|
-
final String? parentSpanId;
|
|
40
|
-
final bool? sampled;
|
|
41
|
-
|
|
42
|
-
const NomosTraceContext({
|
|
43
|
-
this.traceId,
|
|
44
|
-
this.spanId,
|
|
45
|
-
this.parentSpanId,
|
|
46
|
-
this.sampled,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
factory NomosTraceContext.fromJson(Object? value) {
|
|
50
|
-
if (value is! Map) return const NomosTraceContext();
|
|
51
|
-
final m = value.cast<String, Object?>();
|
|
52
|
-
return NomosTraceContext(
|
|
53
|
-
traceId: m['traceId']?.toString(),
|
|
54
|
-
spanId: m['spanId']?.toString(),
|
|
55
|
-
parentSpanId: m['parentSpanId']?.toString(),
|
|
56
|
-
sampled: m['sampled'] is bool ? m['sampled'] as bool : null,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
Map<String, Object?> toJson() => {
|
|
61
|
-
if (traceId != null) 'traceId': traceId,
|
|
62
|
-
if (spanId != null) 'spanId': spanId,
|
|
63
|
-
if (parentSpanId != null) 'parentSpanId': parentSpanId,
|
|
64
|
-
if (sampled != null) 'sampled': sampled,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
bool get isEmpty =>
|
|
68
|
-
traceId == null &&
|
|
69
|
-
spanId == null &&
|
|
70
|
-
parentSpanId == null &&
|
|
71
|
-
sampled == null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/// Structured runtime error detail for the bridge boundary. Keep this data-only: it is safe to serialize, log,
|
|
75
|
-
/// persist, or later attach to an OpenTelemetry span without importing tracing into the core client package.
|
|
76
|
-
class NomosErrorInfo {
|
|
77
|
-
final String code;
|
|
78
|
-
final String message;
|
|
79
|
-
final String component;
|
|
80
|
-
final String? operation;
|
|
81
|
-
final String? workspace;
|
|
82
|
-
final String? domain;
|
|
83
|
-
final String? directiveId;
|
|
84
|
-
final NomosTraceContext trace;
|
|
85
|
-
final Map<String, Object?> attributes;
|
|
86
|
-
final NomosErrorInfo? cause;
|
|
87
|
-
|
|
88
|
-
const NomosErrorInfo({
|
|
89
|
-
required this.code,
|
|
90
|
-
required this.message,
|
|
91
|
-
this.component = 'nomos.client',
|
|
92
|
-
this.operation,
|
|
93
|
-
this.workspace,
|
|
94
|
-
this.domain,
|
|
95
|
-
this.directiveId,
|
|
96
|
-
this.trace = const NomosTraceContext(),
|
|
97
|
-
this.attributes = const {},
|
|
98
|
-
this.cause,
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
factory NomosErrorInfo.legacy(
|
|
102
|
-
Object? message, {
|
|
103
|
-
String code = 'nomos.bridge.error',
|
|
104
|
-
String component = 'nomos.client',
|
|
105
|
-
String? operation,
|
|
106
|
-
NomosTraceContext trace = const NomosTraceContext(),
|
|
107
|
-
}) {
|
|
108
|
-
return NomosErrorInfo(
|
|
109
|
-
code: code,
|
|
110
|
-
message: (message ?? 'the githolon refused the request').toString(),
|
|
111
|
-
component: component,
|
|
112
|
-
operation: operation,
|
|
113
|
-
trace: trace,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
factory NomosErrorInfo.fromJson(
|
|
118
|
-
Object? value, {
|
|
119
|
-
Object? fallbackMessage,
|
|
120
|
-
String? fallbackOperation,
|
|
121
|
-
NomosTraceContext fallbackTrace = const NomosTraceContext(),
|
|
122
|
-
}) {
|
|
123
|
-
if (value is! Map) {
|
|
124
|
-
return NomosErrorInfo.legacy(
|
|
125
|
-
fallbackMessage,
|
|
126
|
-
operation: fallbackOperation,
|
|
127
|
-
trace: fallbackTrace,
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
final m = value.cast<String, Object?>();
|
|
131
|
-
final trace = NomosTraceContext.fromJson(m['trace']);
|
|
132
|
-
return NomosErrorInfo(
|
|
133
|
-
code: (m['code'] ?? 'nomos.bridge.error').toString(),
|
|
134
|
-
message: (m['message'] ??
|
|
135
|
-
fallbackMessage ??
|
|
136
|
-
'the githolon refused the request')
|
|
137
|
-
.toString(),
|
|
138
|
-
component: (m['component'] ?? 'nomos.client').toString(),
|
|
139
|
-
operation: m['operation']?.toString() ?? fallbackOperation,
|
|
140
|
-
workspace: m['workspace']?.toString(),
|
|
141
|
-
domain: m['domain']?.toString(),
|
|
142
|
-
directiveId: m['directiveId']?.toString(),
|
|
143
|
-
trace: trace.isEmpty ? fallbackTrace : trace,
|
|
144
|
-
attributes:
|
|
145
|
-
((m['attributes'] as Map?)?.cast<String, Object?>()) ?? const {},
|
|
146
|
-
cause: m['cause'] == null
|
|
147
|
-
? null
|
|
148
|
-
: NomosErrorInfo.fromJson(m['cause'],
|
|
149
|
-
fallbackOperation: fallbackOperation),
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
factory NomosErrorInfo.fromBridgeMessage(
|
|
154
|
-
Map<String, Object?> message, {
|
|
155
|
-
String? fallbackOperation,
|
|
156
|
-
NomosTraceContext fallbackTrace = const NomosTraceContext(),
|
|
157
|
-
Object? fallbackMessage,
|
|
158
|
-
}) {
|
|
159
|
-
return NomosErrorInfo.fromJson(
|
|
160
|
-
message['errorInfo'],
|
|
161
|
-
fallbackMessage: message['error'] ?? fallbackMessage,
|
|
162
|
-
fallbackOperation: fallbackOperation,
|
|
163
|
-
fallbackTrace: fallbackTrace,
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
Map<String, Object?> toJson() => {
|
|
168
|
-
'code': code,
|
|
169
|
-
'message': message,
|
|
170
|
-
'component': component,
|
|
171
|
-
if (operation != null) 'operation': operation,
|
|
172
|
-
if (workspace != null) 'workspace': workspace,
|
|
173
|
-
if (domain != null) 'domain': domain,
|
|
174
|
-
if (directiveId != null) 'directiveId': directiveId,
|
|
175
|
-
if (!trace.isEmpty) 'trace': trace.toJson(),
|
|
176
|
-
if (attributes.isNotEmpty) 'attributes': attributes,
|
|
177
|
-
if (cause != null) 'cause': cause!.toJson(),
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
/// Attribute map suitable for attaching to a future OTel span/event. The keys are stable and low-cardinality
|
|
181
|
-
/// where possible; high-cardinality values stay explicit (`workspace`, `domain`, directive) so apps can redact.
|
|
182
|
-
Map<String, Object?> toTelemetryAttributes() => {
|
|
183
|
-
'exception.type': code,
|
|
184
|
-
'exception.message': message,
|
|
185
|
-
'nomos.error.code': code,
|
|
186
|
-
'nomos.component': component,
|
|
187
|
-
if (operation != null) 'nomos.operation': operation,
|
|
188
|
-
if (workspace != null) 'nomos.workspace': workspace,
|
|
189
|
-
if (domain != null) 'nomos.domain': domain,
|
|
190
|
-
if (directiveId != null) 'nomos.directive_id': directiveId,
|
|
191
|
-
if (trace.traceId != null) 'trace_id': trace.traceId,
|
|
192
|
-
if (trace.spanId != null) 'span_id': trace.spanId,
|
|
193
|
-
...attributes,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/// A typed refusal surfaced from the githolon's gate (a law refusal, a drift, a malformed op). Carries the
|
|
198
|
-
/// human-first message verbatim plus structured detail for logging, UI mapping, and future OTel export.
|
|
199
|
-
class NomosBridgeError implements Exception {
|
|
200
|
-
final String message;
|
|
201
|
-
final NomosErrorInfo info;
|
|
202
|
-
NomosBridgeError(this.message, {NomosErrorInfo? info})
|
|
203
|
-
: info = info ?? NomosErrorInfo.legacy(message);
|
|
204
|
-
@override
|
|
205
|
-
String toString() => 'NomosBridgeError: $message';
|
|
206
|
-
}
|
|
207
|
-
|
|
208
35
|
/// Live byte-progress of a custody pack transfer (the big initial clone / heavy resync over `/pack`).
|
|
209
36
|
/// [total] is the host's REAL packed size from `Content-Length` (known before the first body byte — the
|
|
210
37
|
/// warm host packs into memory then sends), so [fraction] is a truthful 0→1 bar, never an estimate.
|
|
@@ -1191,14 +1018,13 @@ class NomosBridge {
|
|
|
1191
1018
|
/// ATTESTED READ — serve + SIGN a declared query over a COLOCATED source session's certified fold (the
|
|
1192
1019
|
/// dynamic-source trust lane; architecture/dynamic_source_attested_reads.md). In a [NomosTestHarness.cluster]
|
|
1193
1020
|
/// (one engine plane, many sessions) this fulfils the read IN-PROCESS from the [from] session and returns
|
|
1194
|
-
///
|
|
1195
|
-
/// [offerDirective] `attestations` element, or read
|
|
1196
|
-
/// reader's allow-list. [args] are the
|
|
1197
|
-
/// this view's bound session).
|
|
1021
|
+
/// `{ entry: {queryId, result, attestation:{source_genesis, public_key, …}} }` — pass `result['entry']`
|
|
1022
|
+
/// (the whole entry map) as one [offerDirective] `attestations` element, or read
|
|
1023
|
+
/// `entry['attestation']['source_genesis']` to enrol the source in a reader's allow-list. [args] are the
|
|
1024
|
+
/// query params. [session] is the caller/reader session (defaults to this view's bound session).
|
|
1198
1025
|
/// [attestorSecret] is the source's base64 read-attestor secret (from [authorKeygen]); when omitted the
|
|
1199
1026
|
/// source session's connect-time `authorSecret` signs. [nowMs] stamps the freshness clock (defaults to the
|
|
1200
|
-
/// source's own clock).
|
|
1201
|
-
/// …}}` — pass the whole `entry` as one [offerDirective] `attestations` element.
|
|
1027
|
+
/// source's own clock).
|
|
1202
1028
|
Future<Map<String, Object?>> attestedRead({
|
|
1203
1029
|
required String from,
|
|
1204
1030
|
required String queryId,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
|
+
// remotes are replaceable custody/transport, not truth.
|
|
3
|
+
//
|
|
4
|
+
/// The TEST-ONLY entrypoint (`package:nomos_client/testing.dart`) — the headless harness
|
|
5
|
+
/// (NomosTestHarness drives the REAL githolon under `dart test`, no WebView) and the
|
|
6
|
+
/// node-runner transport it rides. Depend on this ONLY from `dev_dependencies`-scoped
|
|
7
|
+
/// packages: it pulls `dart:io` and process management, which never belong in app code.
|
|
8
|
+
/// The layered-packages emit (`dart.packages.test`) re-exports this as the generated
|
|
9
|
+
/// test package's harness surface.
|
|
10
|
+
library;
|
|
11
|
+
|
|
12
|
+
export 'src/node_runner_transport.dart';
|
|
13
|
+
export 'src/test_harness.dart';
|
package/dart/pubspec.lock
CHANGED
|
@@ -185,6 +185,13 @@ packages:
|
|
|
185
185
|
url: "https://pub.dev"
|
|
186
186
|
source: hosted
|
|
187
187
|
version: "2.0.2"
|
|
188
|
+
nomos_types:
|
|
189
|
+
dependency: "direct main"
|
|
190
|
+
description:
|
|
191
|
+
path: "../dart_types"
|
|
192
|
+
relative: true
|
|
193
|
+
source: path
|
|
194
|
+
version: "0.1.0"
|
|
188
195
|
package_config:
|
|
189
196
|
dependency: transitive
|
|
190
197
|
description:
|
package/dart/pubspec.yaml
CHANGED
|
@@ -11,12 +11,16 @@ description: >-
|
|
|
11
11
|
Nomos 2 Dart frontend types — the hand-written kernel wire types plus the
|
|
12
12
|
code-generated per-domain aggregate + directive-payload types. (De)serializes
|
|
13
13
|
the EXACT serde JSON the Rust kernel + projection produce/consume.
|
|
14
|
-
version: 0.
|
|
14
|
+
version: 0.38.0
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
|
18
18
|
|
|
19
19
|
dependencies:
|
|
20
|
+
# The pure-data core (wire types, offer codec, NomosReads, schema validation, error
|
|
21
|
+
# info). nomos_client depends on and re-exports it, so existing imports are unchanged.
|
|
22
|
+
# For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
|
|
23
|
+
nomos_types: ^0.1.0
|
|
20
24
|
json_schema: ^5.2.2
|
|
21
25
|
crypto: ^3.0.0
|
|
22
26
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# IN-REPO RESOLUTION: nomos_types lives in this monorepo (dsl/dart_types) and is not yet on
|
|
2
|
+
# pub.dev — this override makes `dart pub get` resolve it from source for everyone cloning the
|
|
3
|
+
# repo. Once nomos_types is published, consumers outside the repo resolve the hosted ^0.1.0;
|
|
4
|
+
# this file only affects in-repo development.
|
|
5
|
+
dependency_overrides:
|
|
6
|
+
nomos_types:
|
|
7
|
+
path: ../dart_types
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## 0.1.0
|
|
2
|
+
- Initial release. The pure-data core split out of `nomos_client`: kernel wire types,
|
|
3
|
+
the offer codec, `NomosReads`, the tri-state `NomosSlot`, aggregate metadata, schema
|
|
4
|
+
validation, and the data-only error/trace types (`NomosBridgeError`, `NomosErrorInfo`,
|
|
5
|
+
`NomosTraceContext`) plus the typed diagnostics. No transport, no bridge, no runtime —
|
|
6
|
+
generated per-domain TYPES files depend on only this.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
|
+
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
3
|
+
// wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
|
|
4
|
+
// If a file isn't this / hosting this / authoring for this / proving this — it's gone.
|
|
5
|
+
|
|
6
|
+
/// Nomos 2 pure-data core — the hand-written kernel WIRE/data types with NO transport,
|
|
7
|
+
/// NO bridge, NO runtime, NO Flutter. Generated per-domain TYPES files depend on ONLY
|
|
8
|
+
/// this, so they resolve without pulling in sessions/workspace lifecycle. The
|
|
9
|
+
/// `nomos_client` package depends on and re-exports this barrel, so existing
|
|
10
|
+
/// `package:nomos_client/nomos_client.dart` imports are unchanged.
|
|
11
|
+
///
|
|
12
|
+
/// - The kernel WIRE types (`Value`, `Field`/`WireField`, `Hlc`, `Op`, `FieldOp`,
|
|
13
|
+
/// `Event`, `Schema`/`WireDriver`) — byte-compatible with serde_json.
|
|
14
|
+
/// - The ONE effectful write verb `offer(intent)` + the typed reactive read engine
|
|
15
|
+
/// `NomosReads`.
|
|
16
|
+
/// - The tri-state `NomosSlot<T>`, runtime aggregate metadata, schema validation, and
|
|
17
|
+
/// the data-only error/trace types (`NomosBridgeError`, `NomosErrorInfo`,
|
|
18
|
+
/// `NomosTraceContext`) plus the typed diagnostics.
|
|
19
|
+
library;
|
|
20
|
+
|
|
21
|
+
export 'src/wire.dart';
|
|
22
|
+
export 'src/driver.dart';
|
|
23
|
+
export 'src/offer.dart';
|
|
24
|
+
export 'src/null_slot.dart';
|
|
25
|
+
export 'src/subscriptions.dart';
|
|
26
|
+
export 'src/schema_validation.dart';
|
|
27
|
+
export 'src/aggregate_meta.dart';
|
|
28
|
+
export 'src/error_info.dart';
|
|
29
|
+
export 'src/errors.dart';
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
2
|
+
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
3
|
+
// wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
|
|
4
|
+
// If a file isn't this / hosting this / authoring for this / proving this — it's gone.
|
|
5
|
+
|
|
6
|
+
/// Data-only error/trace types for the bridge boundary. These carry NO transport, NO
|
|
7
|
+
/// bridge, NO runtime — they are pure serializable value types, so they live in
|
|
8
|
+
/// `nomos_types` and are safe to depend on from generated types files + UI code. The
|
|
9
|
+
/// async [NomosBridge] runtime (in `nomos_client`'s `webview_bridge.dart`) builds on them.
|
|
10
|
+
library;
|
|
11
|
+
|
|
12
|
+
/// Trace/span context carried over the bridge as plain JSON. It is intentionally OpenTelemetry-shaped without
|
|
13
|
+
/// importing an OTel SDK: apps can map it to spans later, while Nomos stays dependency-light at the runtime edge.
|
|
14
|
+
class NomosTraceContext {
|
|
15
|
+
final String? traceId;
|
|
16
|
+
final String? spanId;
|
|
17
|
+
final String? parentSpanId;
|
|
18
|
+
final bool? sampled;
|
|
19
|
+
|
|
20
|
+
const NomosTraceContext({
|
|
21
|
+
this.traceId,
|
|
22
|
+
this.spanId,
|
|
23
|
+
this.parentSpanId,
|
|
24
|
+
this.sampled,
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
factory NomosTraceContext.fromJson(Object? value) {
|
|
28
|
+
if (value is! Map) return const NomosTraceContext();
|
|
29
|
+
final m = value.cast<String, Object?>();
|
|
30
|
+
return NomosTraceContext(
|
|
31
|
+
traceId: m['traceId']?.toString(),
|
|
32
|
+
spanId: m['spanId']?.toString(),
|
|
33
|
+
parentSpanId: m['parentSpanId']?.toString(),
|
|
34
|
+
sampled: m['sampled'] is bool ? m['sampled'] as bool : null,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Map<String, Object?> toJson() => {
|
|
39
|
+
if (traceId != null) 'traceId': traceId,
|
|
40
|
+
if (spanId != null) 'spanId': spanId,
|
|
41
|
+
if (parentSpanId != null) 'parentSpanId': parentSpanId,
|
|
42
|
+
if (sampled != null) 'sampled': sampled,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
bool get isEmpty =>
|
|
46
|
+
traceId == null &&
|
|
47
|
+
spanId == null &&
|
|
48
|
+
parentSpanId == null &&
|
|
49
|
+
sampled == null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Structured runtime error detail for the bridge boundary. Keep this data-only: it is safe to serialize, log,
|
|
53
|
+
/// persist, or later attach to an OpenTelemetry span without importing tracing into the core client package.
|
|
54
|
+
class NomosErrorInfo {
|
|
55
|
+
final String code;
|
|
56
|
+
final String message;
|
|
57
|
+
final String component;
|
|
58
|
+
final String? operation;
|
|
59
|
+
final String? workspace;
|
|
60
|
+
final String? domain;
|
|
61
|
+
final String? directiveId;
|
|
62
|
+
final NomosTraceContext trace;
|
|
63
|
+
final Map<String, Object?> attributes;
|
|
64
|
+
final NomosErrorInfo? cause;
|
|
65
|
+
|
|
66
|
+
const NomosErrorInfo({
|
|
67
|
+
required this.code,
|
|
68
|
+
required this.message,
|
|
69
|
+
this.component = 'nomos.client',
|
|
70
|
+
this.operation,
|
|
71
|
+
this.workspace,
|
|
72
|
+
this.domain,
|
|
73
|
+
this.directiveId,
|
|
74
|
+
this.trace = const NomosTraceContext(),
|
|
75
|
+
this.attributes = const {},
|
|
76
|
+
this.cause,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
factory NomosErrorInfo.legacy(
|
|
80
|
+
Object? message, {
|
|
81
|
+
String code = 'nomos.bridge.error',
|
|
82
|
+
String component = 'nomos.client',
|
|
83
|
+
String? operation,
|
|
84
|
+
NomosTraceContext trace = const NomosTraceContext(),
|
|
85
|
+
}) {
|
|
86
|
+
return NomosErrorInfo(
|
|
87
|
+
code: code,
|
|
88
|
+
message: (message ?? 'the githolon refused the request').toString(),
|
|
89
|
+
component: component,
|
|
90
|
+
operation: operation,
|
|
91
|
+
trace: trace,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
factory NomosErrorInfo.fromJson(
|
|
96
|
+
Object? value, {
|
|
97
|
+
Object? fallbackMessage,
|
|
98
|
+
String? fallbackOperation,
|
|
99
|
+
NomosTraceContext fallbackTrace = const NomosTraceContext(),
|
|
100
|
+
}) {
|
|
101
|
+
if (value is! Map) {
|
|
102
|
+
return NomosErrorInfo.legacy(
|
|
103
|
+
fallbackMessage,
|
|
104
|
+
operation: fallbackOperation,
|
|
105
|
+
trace: fallbackTrace,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
final m = value.cast<String, Object?>();
|
|
109
|
+
final trace = NomosTraceContext.fromJson(m['trace']);
|
|
110
|
+
return NomosErrorInfo(
|
|
111
|
+
code: (m['code'] ?? 'nomos.bridge.error').toString(),
|
|
112
|
+
message: (m['message'] ??
|
|
113
|
+
fallbackMessage ??
|
|
114
|
+
'the githolon refused the request')
|
|
115
|
+
.toString(),
|
|
116
|
+
component: (m['component'] ?? 'nomos.client').toString(),
|
|
117
|
+
operation: m['operation']?.toString() ?? fallbackOperation,
|
|
118
|
+
workspace: m['workspace']?.toString(),
|
|
119
|
+
domain: m['domain']?.toString(),
|
|
120
|
+
directiveId: m['directiveId']?.toString(),
|
|
121
|
+
trace: trace.isEmpty ? fallbackTrace : trace,
|
|
122
|
+
attributes:
|
|
123
|
+
((m['attributes'] as Map?)?.cast<String, Object?>()) ?? const {},
|
|
124
|
+
cause: m['cause'] == null
|
|
125
|
+
? null
|
|
126
|
+
: NomosErrorInfo.fromJson(m['cause'],
|
|
127
|
+
fallbackOperation: fallbackOperation),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
factory NomosErrorInfo.fromBridgeMessage(
|
|
132
|
+
Map<String, Object?> message, {
|
|
133
|
+
String? fallbackOperation,
|
|
134
|
+
NomosTraceContext fallbackTrace = const NomosTraceContext(),
|
|
135
|
+
Object? fallbackMessage,
|
|
136
|
+
}) {
|
|
137
|
+
return NomosErrorInfo.fromJson(
|
|
138
|
+
message['errorInfo'],
|
|
139
|
+
fallbackMessage: message['error'] ?? fallbackMessage,
|
|
140
|
+
fallbackOperation: fallbackOperation,
|
|
141
|
+
fallbackTrace: fallbackTrace,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
Map<String, Object?> toJson() => {
|
|
146
|
+
'code': code,
|
|
147
|
+
'message': message,
|
|
148
|
+
'component': component,
|
|
149
|
+
if (operation != null) 'operation': operation,
|
|
150
|
+
if (workspace != null) 'workspace': workspace,
|
|
151
|
+
if (domain != null) 'domain': domain,
|
|
152
|
+
if (directiveId != null) 'directiveId': directiveId,
|
|
153
|
+
if (!trace.isEmpty) 'trace': trace.toJson(),
|
|
154
|
+
if (attributes.isNotEmpty) 'attributes': attributes,
|
|
155
|
+
if (cause != null) 'cause': cause!.toJson(),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/// Attribute map suitable for attaching to a future OTel span/event. The keys are stable and low-cardinality
|
|
159
|
+
/// where possible; high-cardinality values stay explicit (`workspace`, `domain`, directive) so apps can redact.
|
|
160
|
+
Map<String, Object?> toTelemetryAttributes() => {
|
|
161
|
+
'exception.type': code,
|
|
162
|
+
'exception.message': message,
|
|
163
|
+
'nomos.error.code': code,
|
|
164
|
+
'nomos.component': component,
|
|
165
|
+
if (operation != null) 'nomos.operation': operation,
|
|
166
|
+
if (workspace != null) 'nomos.workspace': workspace,
|
|
167
|
+
if (domain != null) 'nomos.domain': domain,
|
|
168
|
+
if (directiveId != null) 'nomos.directive_id': directiveId,
|
|
169
|
+
if (trace.traceId != null) 'trace_id': trace.traceId,
|
|
170
|
+
if (trace.spanId != null) 'span_id': trace.spanId,
|
|
171
|
+
...attributes,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/// A typed refusal surfaced from the githolon's gate (a law refusal, a drift, a malformed op). Carries the
|
|
176
|
+
/// human-first message verbatim plus structured detail for logging, UI mapping, and future OTel export.
|
|
177
|
+
class NomosBridgeError implements Exception {
|
|
178
|
+
final String message;
|
|
179
|
+
final NomosErrorInfo info;
|
|
180
|
+
NomosBridgeError(this.message, {NomosErrorInfo? info})
|
|
181
|
+
: info = info ?? NomosErrorInfo.legacy(message);
|
|
182
|
+
@override
|
|
183
|
+
String toString() => 'NomosBridgeError: $message';
|
|
184
|
+
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
/// All extend [NomosBridgeError] so existing `catch (NomosBridgeError)` handlers still catch them.
|
|
15
15
|
library;
|
|
16
16
|
|
|
17
|
-
import '
|
|
17
|
+
import 'error_info.dart' show NomosBridgeError, NomosErrorInfo;
|
|
18
18
|
|
|
19
19
|
/// Mint the MOST SPECIFIC typed error for a structured refusal — the one construction point the bridge
|
|
20
20
|
/// uses everywhere it surfaces an `errorInfo`. A `nomos.custody.*` code becomes a [CustodyError] (typed,
|