@githolon/dsl 0.111.0 → 0.111.1
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 +11 -3
- package/dart/lib/src/reception/dart_reception.dart +48 -30
- package/dart/lib/src/runner/node-entry.mjs +134 -19
- package/dart/lib/src/runtime_v2_gateway.dart +1 -22
- package/dart/lib/src/runtime_v2_transport.dart +5 -1
- package/dart/lib/src/write_progress.dart +48 -0
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/child_authentication_repair_test.dart +46 -0
- package/dart/test/runtime_v2_gateway_test.dart +29 -0
- package/dart/test/write_progress_test.dart +56 -0
- package/dart_types/CHANGELOG.md +4 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +90 -1
- package/dart_types/lib/src/runtime_outcome.dart +46 -31
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +2 -2
- package/src/codegen_dart_facade.ts +1 -0
- package/src/compile_package_main.ts +4 -3
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.66.9
|
|
2
|
+
|
|
3
|
+
- Prepare delayed workspace enrollment inside Peer Office and retry a proven non-admitted write once. Generated applications can observe preparation while retaining their draft.
|
|
4
|
+
|
|
5
|
+
## 0.66.8
|
|
6
|
+
|
|
7
|
+
- Recover expired or missing sync credentials from typed failures. Preserve authorization and domain refusals without refreshing credentials based on diagnostic wording or HTTP 403.
|
|
8
|
+
|
|
1
9
|
## 0.66.7
|
|
2
10
|
|
|
3
11
|
- Recover sync after loss of the upstream bookmark by fetching provider history and allowing the kernel to verify a shared ancestor. Preserve pending local work and reject unrelated history through the existing admission gate.
|
|
@@ -18,7 +26,7 @@
|
|
|
18
26
|
|
|
19
27
|
## 0.66.3
|
|
20
28
|
|
|
21
|
-
-
|
|
29
|
+
- Recover expired or missing sync credentials from typed failures. Preserve authorization and domain refusals without refreshing credentials based on diagnostic wording or HTTP 403.
|
|
22
30
|
|
|
23
31
|
## 0.66.2
|
|
24
32
|
|
|
@@ -114,11 +122,11 @@
|
|
|
114
122
|
|
|
115
123
|
## 0.64.47
|
|
116
124
|
|
|
117
|
-
-
|
|
125
|
+
- Recover expired or missing sync credentials from typed failures. Preserve authorization and domain refusals without refreshing credentials based on diagnostic wording or HTTP 403.
|
|
118
126
|
|
|
119
127
|
## 0.64.46
|
|
120
128
|
|
|
121
|
-
-
|
|
129
|
+
- Recover expired or missing sync credentials from typed failures. Preserve authorization and domain refusals without refreshing credentials based on diagnostic wording or HTTP 403.
|
|
122
130
|
|
|
123
131
|
## 0.64.45
|
|
124
132
|
|
|
@@ -17,6 +17,7 @@ library;
|
|
|
17
17
|
import 'package:meta/meta.dart' show internal;
|
|
18
18
|
|
|
19
19
|
import 'dart:async';
|
|
20
|
+
import '../write_progress.dart';
|
|
20
21
|
import 'dart:convert';
|
|
21
22
|
import 'dart:developer' as developer;
|
|
22
23
|
import 'dart:typed_data';
|
|
@@ -879,7 +880,16 @@ class DartReception {
|
|
|
879
880
|
);
|
|
880
881
|
}
|
|
881
882
|
|
|
883
|
+
final Map<String, void Function(NomosWriteProgress)> _writeObservers = {};
|
|
884
|
+
|
|
882
885
|
void _onRuntimeEvent(nomos_protocol.RuntimeEvent event) {
|
|
886
|
+
if (event.hasWritePreparation()) {
|
|
887
|
+
final progress = event.writePreparation;
|
|
888
|
+
_eventPlane._writeObservers[progress.requestId]?.call(
|
|
889
|
+
const NomosWriteProgress(NomosWritePhase.preparing),
|
|
890
|
+
);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
883
893
|
if (event.hasReady()) {
|
|
884
894
|
final stale = _staleBundleError(event.ready.runtimeVersion);
|
|
885
895
|
if (stale != null && !allowStaleRunnerBundle) {
|
|
@@ -1719,40 +1729,48 @@ class DartReception {
|
|
|
1719
1729
|
// ignore: avoid_print
|
|
1720
1730
|
print('[nomos-offer] dispatch ${call.domain}/${call.directive} in '
|
|
1721
1731
|
'$workspace using ${authenticationProof.name}');
|
|
1722
|
-
Future<nomos_protocol.CallResponse> attempt() {
|
|
1732
|
+
Future<nomos_protocol.CallResponse> attempt() async {
|
|
1723
1733
|
final requestNumber = ++plane._sequences.request;
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1734
|
+
final requestId = '$runtimeSession:offer:$requestNumber';
|
|
1735
|
+
final observer = NomosWrite.captureObserver();
|
|
1736
|
+
if (observer != null) plane._writeObservers[requestId] = observer;
|
|
1737
|
+
try {
|
|
1738
|
+
return await kernelTransport.callKernel(
|
|
1739
|
+
session: runtimeSession,
|
|
1740
|
+
request: nomos_protocol.CallRequest(
|
|
1741
|
+
protocolVersion: 1,
|
|
1742
|
+
requestId: requestId,
|
|
1743
|
+
offer: nomos_protocol.OfferRequest(
|
|
1744
|
+
call: nomos_protocol.DirectiveCall(
|
|
1745
|
+
domain: call.domain,
|
|
1746
|
+
directive: call.directive,
|
|
1747
|
+
operation: google_protobuf.Any(
|
|
1748
|
+
typeUrl: call.protobufType,
|
|
1749
|
+
value: call.protobufPayload,
|
|
1750
|
+
),
|
|
1736
1751
|
),
|
|
1752
|
+
authoring: nomos_protocol.AuthoringOptions(
|
|
1753
|
+
actor: actor ?? '',
|
|
1754
|
+
// Ordinary generated calls select a peer-runtime credential
|
|
1755
|
+
// capability below. An explicit secret is a temporary operator
|
|
1756
|
+
// compatibility lane and remains client-supplied until removed.
|
|
1757
|
+
authorSecret: explicitSecret == null
|
|
1758
|
+
? const <int>[]
|
|
1759
|
+
: base64Decode(explicitSecret),
|
|
1760
|
+
deferProjection: true,
|
|
1761
|
+
spans: true,
|
|
1762
|
+
),
|
|
1763
|
+
controllerLawHash: domainHash,
|
|
1764
|
+
conflictSnapshots: conflictSnapshots,
|
|
1765
|
+
birthCertificate: birthCertificate,
|
|
1737
1766
|
),
|
|
1738
|
-
authoring: nomos_protocol.AuthoringOptions(
|
|
1739
|
-
actor: actor ?? '',
|
|
1740
|
-
// Ordinary generated calls select a peer-runtime credential
|
|
1741
|
-
// capability below. An explicit secret is a temporary operator
|
|
1742
|
-
// compatibility lane and remains client-supplied until removed.
|
|
1743
|
-
authorSecret: explicitSecret == null
|
|
1744
|
-
? const <int>[]
|
|
1745
|
-
: base64Decode(explicitSecret),
|
|
1746
|
-
deferProjection: true,
|
|
1747
|
-
spans: true,
|
|
1748
|
-
),
|
|
1749
|
-
controllerLawHash: domainHash,
|
|
1750
|
-
conflictSnapshots: conflictSnapshots,
|
|
1751
|
-
birthCertificate: birthCertificate,
|
|
1752
1767
|
),
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1768
|
+
credentialUse: credentialUse,
|
|
1769
|
+
);
|
|
1770
|
+
} finally {
|
|
1771
|
+
plane._writeObservers.remove(requestId);
|
|
1772
|
+
observer?.call(const NomosWriteProgress(NomosWritePhase.running));
|
|
1773
|
+
}
|
|
1756
1774
|
}
|
|
1757
1775
|
|
|
1758
1776
|
var response = await attempt();
|
|
@@ -5995,7 +5995,7 @@ var CustodyBreakPolicySchema = /* @__PURE__ */ enumDesc(file_nomos_runtime_v2_re
|
|
|
5995
5995
|
var CustodyBreakPolicy = /* @__PURE__ */ tsEnum(CustodyBreakPolicySchema);
|
|
5996
5996
|
|
|
5997
5997
|
// ../../adapter/proto/nomos/runtime/v2/observability_desk_pb.js
|
|
5998
|
-
var file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc("Cilub21vcy9ydW50aW1lL3YyL29ic2VydmFiaWxpdHlfZGVzay5wcm90bxIQbm9tb3MucnVudGltZS52MiJCCgxUcmFjZUNvbnRleHQSEAoIdHJhY2VfaWQYASABKAwSDwoHc3Bhbl9pZBgCIAEoDBIPCgdzYW1wbGVkGAMgASgIIp0CCg5SdW50aW1lRmFpbHVyZRIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEQoJY29tcG9uZW50GAMgASgJEhYKCXdvcmtzcGFjZRgEIAEoCUgAiAEBEhMKBmRvbWFpbhgFIAEoCUgBiAEBEhYKCWRpcmVjdGl2ZRgGIAEoCUgCiAEBEjkKCmF0dHJpYnV0ZXMYByADKAsyJS5ub21vcy5ydW50aW1lLnYyLkRpYWdub3N0aWNBdHRyaWJ1dGUSMgoEa2luZBgIIAEoDjIkLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZUZhaWx1cmVLaW5kQgwKCl93b3Jrc3BhY2VCCQoHX2RvbWFpbkIMCgpfZGlyZWN0aXZlIr4BChJSdW50aW1lVW5hdmFpbGFibGUSOgoGcmVhc29uGAEgASgOMioubm9tb3MucnVudGltZS52Mi5SdW50aW1lVW5hdmFpbGFibGVSZWFzb24SEQoJd29ya3NwYWNlGAIgASgJEhEKCXJldHJ5YWJsZRgDIAEoCBIfChJyZXRyeV9hZnRlcl9taWxsaXMYBCABKA1IAIgBARIOCgZkZXRhaWwYBSABKAlCFQoTX3JldHJ5X2FmdGVyX21pbGxpcyJ+
|
|
5998
|
+
var file_nomos_runtime_v2_observability_desk = /* @__PURE__ */ fileDesc("Cilub21vcy9ydW50aW1lL3YyL29ic2VydmFiaWxpdHlfZGVzay5wcm90bxIQbm9tb3MucnVudGltZS52MiJCCgxUcmFjZUNvbnRleHQSEAoIdHJhY2VfaWQYASABKAwSDwoHc3Bhbl9pZBgCIAEoDBIPCgdzYW1wbGVkGAMgASgIIp0CCg5SdW50aW1lRmFpbHVyZRIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEQoJY29tcG9uZW50GAMgASgJEhYKCXdvcmtzcGFjZRgEIAEoCUgAiAEBEhMKBmRvbWFpbhgFIAEoCUgBiAEBEhYKCWRpcmVjdGl2ZRgGIAEoCUgCiAEBEjkKCmF0dHJpYnV0ZXMYByADKAsyJS5ub21vcy5ydW50aW1lLnYyLkRpYWdub3N0aWNBdHRyaWJ1dGUSMgoEa2luZBgIIAEoDjIkLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZUZhaWx1cmVLaW5kQgwKCl93b3Jrc3BhY2VCCQoHX2RvbWFpbkIMCgpfZGlyZWN0aXZlIr4BChJSdW50aW1lVW5hdmFpbGFibGUSOgoGcmVhc29uGAEgASgOMioubm9tb3MucnVudGltZS52Mi5SdW50aW1lVW5hdmFpbGFibGVSZWFzb24SEQoJd29ya3NwYWNlGAIgASgJEhEKCXJldHJ5YWJsZRgDIAEoCBIfChJyZXRyeV9hZnRlcl9taWxsaXMYBCABKA1IAIgBARIOCgZkZXRhaWwYBSABKAlCFQoTX3JldHJ5X2FmdGVyX21pbGxpcyJ+Cg5SdW50aW1lUmVmdXNhbBI2CgZyZWFzb24YASABKA4yJi5ub21vcy5ydW50aW1lLnYyLlJ1bnRpbWVSZWZ1c2FsUmVhc29uEhEKCXdvcmtzcGFjZRgCIAEoCRIRCglyZXRyeWFibGUYAyABKAgSDgoGZGV0YWlsGAQgASgJIqUBChNEaWFnbm9zdGljQXR0cmlidXRlEgwKBG5hbWUYASABKAkSFgoMc3RyaW5nX3ZhbHVlGAIgASgJSAASFwoNaW50ZWdlcl92YWx1ZRgDIAEoEkgAEhYKDGRvdWJsZV92YWx1ZRgEIAEoAUgAEhcKDWJvb2xlYW5fdmFsdWUYBSABKAhIABIVCgtieXRlc192YWx1ZRgGIAEoDEgAQgcKBXZhbHVlIqQLCgxSdW50aW1lRXZlbnQSEAoIc2VxdWVuY2UYASABKAQSFAoHc2Vzc2lvbhgCIAEoCUgBiAEBEi8KBXJlYWR5GAogASgLMh4ubm9tb3MucnVudGltZS52Mi5SdW50aW1lUmVhZHlIABI3Cg13YXRjaF9jaGFuZ2VkGAsgASgLMh4ubm9tb3MucnVudGltZS52Mi5XYXRjaENoYW5nZWRIABI5Cg5zeW5jX2NvbXBsZXRlZBgMIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU3luY0NvbXBsZXRlZEgAEjUKDGxpbmtfY2hhbmdlZBgNIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuTGlua0NoYW5nZWRIABI5Cg5zaWduYWxfY2hhbmdlZBgOIAEoCzIfLm5vbW9zLnJ1bnRpbWUudjIuU2lnbmFsQ2hhbmdlZEgAEjsKD2N1c3RvZHlfY2hhbmdlZBgPIAEoCzIgLm5vbW9zLnJ1bnRpbWUudjIuQ3VzdG9keUNoYW5nZWRIABJCChNsb2NhbF93b3JrX3JlamVjdGVkGBAgASgLMiMubm9tb3MucnVudGltZS52Mi5Mb2NhbFdvcmtSZWplY3RlZEgAEjMKC2xhd19jaGFuZ2VkGBEgASgLMhwubm9tb3MucnVudGltZS52Mi5MYXdDaGFuZ2VkSAASQwoPa2VybmVsX3Byb2dyZXNzGBIgASgLMigubm9tb3MucnVudGltZS52Mi5LZXJuZWxQcm9ncmVzc09ic2VydmVkSAASLQoEc3BhbhgTIAEoCzIdLm5vbW9zLnJ1bnRpbWUudjIuUnVudGltZVNwYW5IABI/ChF0cmFuc2Zlcl9wcm9ncmVzcxgUIAEoCzIiLm5vbW9zLnJ1bnRpbWUudjIuVHJhbnNmZXJQcm9ncmVzc0gAEkkKFG1haW50ZW5hbmNlX3Byb2dyZXNzGBUgASgLMikubm9tb3MucnVudGltZS52Mi5SZWFkTWFpbnRlbmFuY2VQcm9ncmVzc0gAEjsKDXNvY2tldF9lZmZlY3QYFiABKAsyIi5ub21vcy5ydW50aW1lLnYyLlBlZXJTb2NrZXRFZmZlY3RIABJUChxjcmVkZW50aWFsX3JlZnJlc2hfcmVxdWVzdGVkGBcgASgLMiwubm9tb3MucnVudGltZS52Mi5DcmVkZW50aWFsUmVmcmVzaFJlcXVlc3RlZEgAElIKG3JlY2VpdmluZ19ncm91cF9jb252ZXJnZW5jZRgYIAEoCzIrLm5vbW9zLnJ1bnRpbWUudjIuUmVjZWl2aW5nR3JvdXBDb252ZXJnZW5jZUgAEkoKF21vZGVsX2Fkb3B0aW9uX3Byb2dyZXNzGBkgASgLMicubm9tb3MucnVudGltZS52Mi5Nb2RlbEFkb3B0aW9uUHJvZ3Jlc3NIABI7Cg9mb2xsb3dzX3N1bW1hcnkYGiABKAsyIC5ub21vcy5ydW50aW1lLnYyLkZvbGxvd3NTdW1tYXJ5SAASRAoUbG9jYWxfY29weV9wcmVzZXJ2ZWQYGyABKAsyJC5ub21vcy5ydW50aW1lLnYyLlByZXNlcnZlZExvY2FsQ29weUgAEk4KGWZvcmVpZ25fcGxhY2VtZW50X2lnbm9yZWQYHCABKAsyKS5ub21vcy5ydW50aW1lLnYyLkZvcmVpZ25QbGFjZW1lbnRJZ25vcmVkSAASQwoTYmluZGluZ19xdWFyYW50aW5lZBgdIAEoCzIkLm5vbW9zLnJ1bnRpbWUudjIuUXVhcmFudGluZWRCaW5kaW5nSAASPwoRd3JpdGVfcHJlcGFyYXRpb24YHiABKAsyIi5ub21vcy5ydW50aW1lLnYyLldyaXRlUHJlcGFyYXRpb25IAEIHCgVldmVudEIKCghfc2Vzc2lvbiK8AQoORm9sbG93c1N1bW1hcnkSEAoIZm9sbG93ZWQYASABKA0SDwoHc2V0dGxlZBgCIAEoDRIMCgRsaXZlGAMgASgNEjcKCndvcmtzcGFjZXMYBCADKAsyIy5ub21vcy5ydW50aW1lLnYyLkZvbGxvd09ic2VydmF0aW9uEiQKF29ic2VydmVkX2F0X3VuaXhfbWlsbGlzGAUgASgESACIAQFCGgoYX29ic2VydmVkX2F0X3VuaXhfbWlsbGlzItECChFGb2xsb3dPYnNlcnZhdGlvbhIRCgl3b3Jrc3BhY2UYASABKAkSNwoFcGhhc2UYAiABKA4yKC5ub21vcy5ydW50aW1lLnYyLkZvbGxvd09ic2VydmF0aW9uUGhhc2USDAoEbGl2ZRgDIAEoCBITCgZkZXRhaWwYBCABKAlIAIgBARIhChRyZXRyeV9hdF91bml4X21pbGxpcxgFIAEoBEgBiAEBEh8KEmR1ZV9hdF91bml4X21pbGxpcxgGIAEoBEgCiAEBEhQKB2F0dGVtcHQYByABKA1IA4gBARIaCg1hY3RpdmVfZWZmZWN0GAggASgJSASIAQFCCQoHX2RldGFpbEIXChVfcmV0cnlfYXRfdW5peF9taWxsaXNCFQoTX2R1ZV9hdF91bml4X21pbGxpc0IKCghfYXR0ZW1wdEIQCg5fYWN0aXZlX2VmZmVjdCJWChpDcmVkZW50aWFsUmVmcmVzaFJlcXVlc3RlZBI4CgdwZW5kaW5nGAEgASgLMicubm9tb3MucnVudGltZS52Mi5Db3JyZXNwb25kZW5jZVBlbmRpbmciPgoMUnVudGltZVJlYWR5EhcKD3J1bnRpbWVfdmVyc2lvbhgBIAEoCRIVCg1rZXJuZWxfc2hhMjU2GAIgASgMIvwBCgxXYXRjaENoYW5nZWQSFwoPc3Vic2NyaXB0aW9uX2lkGAEgASgJEhMKC3Jlc3VsdF91c2RhGAIgASgMEjYKB2ZhaWx1cmUYAyABKAsyIC5ub21vcy5ydW50aW1lLnYyLlJ1bnRpbWVGYWlsdXJlSACIAQESNQoSYXBwbGljYXRpb25fcmVzdWx0GAQgASgLMhQuZ29vZ2xlLnByb3RvYnVmLkFueUgBiAEBEhoKDWludGVnZXJfdmFsdWUYBSABKANIAogBAUIKCghfZmFpbHVyZUIVChNfYXBwbGljYXRpb25fcmVzdWx0QhAKDl9pbnRlZ2VyX3ZhbHVlIpwBCg1TeW5jQ29tcGxldGVkEg4KBnJlYXNvbhgBIAEoCRI3CgZyZXN1bHQYAiABKAsyJy5ub21vcy5ydW50aW1lLnYyLlN5bmNXb3Jrc3BhY2VSZXNwb25zZRI2CgdmYWlsdXJlGAMgASgLMiAubm9tb3MucnVudGltZS52Mi5SdW50aW1lRmFpbHVyZUgAiAEBQgoKCF9mYWlsdXJlIjsKC0xpbmtDaGFuZ2VkEiwKBnN0YXR1cxgBIAEoDjIcLm5vbW9zLnJ1bnRpbWUudjIuTGlua1N0YXR1cyI4Cg1TaWduYWxDaGFuZ2VkEg4KBmRvbWFpbhgBIAEoCRIXCg9wcm9qZWN0aW9uX3VzZGEYAiABKAwiUAoKTGF3Q2hhbmdlZBIOCgZkb21haW4YASABKAkSFgoOcGFja2FnZV9zaGEyNTYYAiABKAkSGgoSY29tcGF0aWJpbGl0eV91c2RhGAMgASgMIt0BCgtSdW50aW1lU3BhbhIQCgh0cmFjZV9pZBgBIAEoDBIPCgdzcGFuX2lkGAIgASgMEhsKDnBhcmVudF9zcGFuX2lkGAMgASgMSACIAQESDAoEbmFtZRgEIAEoCRIaChJzdGFydGVkX3VuaXhfbmFub3MYBSABKAQSFgoOZHVyYXRpb25fbmFub3MYBiABKAQSOQoKYXR0cmlidXRlcxgHIAMoCzIlLm5vbW9zLnJ1bnRpbWUudjIuRGlhZ25vc3RpY0F0dHJpYnV0ZUIRCg9fcGFyZW50X3NwYW5faWQi6gEKFktlcm5lbFByb2dyZXNzT2JzZXJ2ZWQSOQoIc25hcHNob3QYASABKAsyJy5ub21vcy5rZXJuZWwudjEuS2VybmVsUHJvZ3Jlc3NTbmFwc2hvdBIkChxob3N0X29ic2VydmVkX2VsYXBzZWRfbWljcm9zGAIgASgEEioKImhvc3Rfb2JzZXJ2ZWRfcGhhc2VfZWxhcHNlZF9taWNyb3MYAyABKAQSHgoWcHJvY2Vzc19yZXNpZGVudF9ieXRlcxgEIAEoBBIjChtwcm9jZXNzX3BlYWtfcmVzaWRlbnRfYnl0ZXMYBSABKAQiggEKEFRyYW5zZmVyUHJvZ3Jlc3MSFgoOcmVjZWl2ZWRfYnl0ZXMYASABKAQSGAoLdG90YWxfYnl0ZXMYAiABKARIAIgBARIsCgRraW5kGAMgASgOMh4ubm9tb3MucnVudGltZS52Mi5UcmFuc2ZlcktpbmRCDgoMX3RvdGFsX2J5dGVzIjkKEFdyaXRlUHJlcGFyYXRpb24SEgoKcmVxdWVzdF9pZBgBIAEoCRIRCgl3b3Jrc3BhY2UYAiABKAkqygEKElJ1bnRpbWVGYWlsdXJlS2luZBIkCiBSVU5USU1FX0ZBSUxVUkVfS0lORF9VTlNQRUNJRklFRBAAEiEKHVJVTlRJTUVfRkFJTFVSRV9LSU5EX0lOVEVSTkFMEAESIQodUlVOVElNRV9GQUlMVVJFX0tJTkRfUFJPVE9DT0wQAhIiCh5SVU5USU1FX0ZBSUxVUkVfS0lORF9JTlRFR1JJVFkQAxIkCiBSVU5USU1FX0ZBSUxVUkVfS0lORF9VTlNVUFBPUlRFRBAEKqcDChhSdW50aW1lVW5hdmFpbGFibGVSZWFzb24SKgomUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fVU5TUEVDSUZJRUQQABIyCi5SVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9SRU1PVEVfT05MWV9PRkZMSU5FEAESMQotUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fUkVNT1RFX1VOUkVBQ0hBQkxFEAISLQopUlVOVElNRV9VTkFWQUlMQUJMRV9SRUFTT05fUkVNT1RFX1RJTUVPVVQQAxI2CjJSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9MT0NBTF9SRVBMSUNBX05PVF9SRUFEWRAEEjUKMVJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX0NSRURFTlRJQUxfVU5BVkFJTEFCTEUQBRIwCixSVU5USU1FX1VOQVZBSUxBQkxFX1JFQVNPTl9XT1JLU1BBQ0VfT1BFTklORxAGEigKJFJVTlRJTUVfVU5BVkFJTEFCTEVfUkVBU09OX1BFRVJfQlVTWRAHKvABChRSdW50aW1lUmVmdXNhbFJlYXNvbhImCiJSVU5USU1FX1JFRlVTQUxfUkVBU09OX1VOU1BFQ0lGSUVEEAASLQopUlVOVElNRV9SRUZVU0FMX1JFQVNPTl9JTlZBTElEX0NSRURFTlRJQUwQARIoCiRSVU5USU1FX1JFRlVTQUxfUkVBU09OX0FDQ0VTU19ERU5JRUQQAhIrCidSVU5USU1FX1JFRlVTQUxfUkVBU09OX1BMQUNFTUVOVF9QT0xJQ1kQAxIqCiZSVU5USU1FX1JFRlVTQUxfUkVBU09OX1NFU1NJT05fVU5CT1VORBAEKpUEChZGb2xsb3dPYnNlcnZhdGlvblBoYXNlEigKJEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9VTlNQRUNJRklFRBAAEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9ERVNJUkVEEAESIAocRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0RVRRACEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9SVU5OSU5HEAMSJAogRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1NFVFRMRUQQBBIwCixGT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfQVdBSVRJTkdfREVQRU5ERU5DWRAFEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9PRkZMSU5FEAYSLworRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX0lOVkFMSURfQ1JFREVOVElBTBAHEiQKIEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9CQUNLT0ZGEAgSLAooRk9MTE9XX09CU0VSVkFUSU9OX1BIQVNFX1JFQk9STl9SRU1PVEVMWRAJEiwKKEZPTExPV19PQlNFUlZBVElPTl9QSEFTRV9SRVBMQUNJTkdfTE9DQUwQChIyCi5GT0xMT1dfT0JTRVJWQVRJT05fUEhBU0VfTE9DQUxfQ09QWV9VTlJFQURBQkxFEAsqVwoKTGlua1N0YXR1cxIbChdMSU5LX1NUQVRVU19VTlNQRUNJRklFRBAAEhQKEExJTktfU1RBVFVTX09QRU4QARIWChJMSU5LX1NUQVRVU19DTE9TRUQQAip2CgxUcmFuc2ZlcktpbmQSHQoZVFJBTlNGRVJfS0lORF9VTlNQRUNJRklFRBAAEhcKE1RSQU5TRkVSX0tJTkRfREVMVEEQARIWChJUUkFOU0ZFUl9LSU5EX0ZVTEwQAhIWChJUUkFOU0ZFUl9LSU5EX1BVU0gQA2IGcHJvdG8z", [file_google_protobuf_any, file_nomos_kernel_v1_progress, file_nomos_runtime_v2_correspondence_desk, file_nomos_runtime_v2_custody_desk, file_nomos_runtime_v2_placement_desk, file_nomos_runtime_v2_maintenance_desk, file_nomos_runtime_v2_model_adoption_desk, file_nomos_runtime_v2_receiving_group_desk, file_nomos_runtime_v2_recovery_desk]);
|
|
5999
5999
|
var RuntimeFailureSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 1);
|
|
6000
6000
|
var RuntimeUnavailableSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 2);
|
|
6001
6001
|
var RuntimeRefusalSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 3);
|
|
@@ -6009,6 +6009,7 @@ var WatchChangedSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_obser
|
|
|
6009
6009
|
var SyncCompletedSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 11);
|
|
6010
6010
|
var LinkChangedSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 12);
|
|
6011
6011
|
var RuntimeSpanSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 15);
|
|
6012
|
+
var WritePreparationSchema = /* @__PURE__ */ messageDesc(file_nomos_runtime_v2_observability_desk, 18);
|
|
6012
6013
|
var RuntimeFailureKindSchema = /* @__PURE__ */ enumDesc(file_nomos_runtime_v2_observability_desk, 0);
|
|
6013
6014
|
var RuntimeFailureKind = /* @__PURE__ */ tsEnum(RuntimeFailureKindSchema);
|
|
6014
6015
|
var RuntimeUnavailableReasonSchema = /* @__PURE__ */ enumDesc(file_nomos_runtime_v2_observability_desk, 1);
|
|
@@ -16356,6 +16357,18 @@ var CredentialSessions = class {
|
|
|
16356
16357
|
// ../src/runtime/credential_recovery_desk.ts
|
|
16357
16358
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
16358
16359
|
|
|
16360
|
+
// ../src/runtime/credential_failure.ts
|
|
16361
|
+
init_define_NOMOS_KERNEL_RELEASE();
|
|
16362
|
+
function recoverableCredential(failure) {
|
|
16363
|
+
return failure.code === "nomos.auth.token_expired" || failure.code === "nomos.auth.token_missing";
|
|
16364
|
+
}
|
|
16365
|
+
function syncNeedsCredentialRefresh(result, failure) {
|
|
16366
|
+
if (failure !== void 0 && recoverableCredential(failure)) return true;
|
|
16367
|
+
const offer = result?.offerReceipt?.outcome;
|
|
16368
|
+
const pushNeedsRefresh = offer?.case === "failure" ? recoverableCredential(offer.value) : result?.pushError?.status === 401;
|
|
16369
|
+
return pushNeedsRefresh || result?.discoveryError?.status === 401;
|
|
16370
|
+
}
|
|
16371
|
+
|
|
16359
16372
|
// ../src/runtime/credential_renewal.ts
|
|
16360
16373
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
16361
16374
|
var RENEW_BEFORE_MILLIS = 5 * 6e4;
|
|
@@ -16621,7 +16634,7 @@ var CredentialRecoveryDesk = class {
|
|
|
16621
16634
|
return false;
|
|
16622
16635
|
}
|
|
16623
16636
|
observeSync(session, event) {
|
|
16624
|
-
if (!syncNeedsCredentialRefresh(event) || this.#tokenless(session)) return;
|
|
16637
|
+
if (!syncNeedsCredentialRefresh(event.result, event.failure) || this.#tokenless(session)) return;
|
|
16625
16638
|
this.#prune();
|
|
16626
16639
|
const capability = this.#ports.capabilityFor(session);
|
|
16627
16640
|
const existing = this.#active.get(capability);
|
|
@@ -16823,15 +16836,6 @@ var CredentialRecoveryDesk = class {
|
|
|
16823
16836
|
this.#completed.clear();
|
|
16824
16837
|
}
|
|
16825
16838
|
};
|
|
16826
|
-
function recoverableCredential(failure) {
|
|
16827
|
-
return failure.code === "nomos.auth.token_expired" || failure.code === "nomos.auth.token_missing";
|
|
16828
|
-
}
|
|
16829
|
-
function syncNeedsCredentialRefresh(event) {
|
|
16830
|
-
const failures = [event.result?.pushError, event.result?.discoveryError];
|
|
16831
|
-
if (failures.some((failure) => failure?.status === 401 || failure?.status === 403)) return true;
|
|
16832
|
-
const text = `${event.failure?.message ?? ""} ${failures.map((failure) => failure?.message ?? "").join(" ")}`.toLowerCase();
|
|
16833
|
-
return text.includes("unauthenticated") || text.includes("token expired") || text.includes("invalid token");
|
|
16834
|
-
}
|
|
16835
16839
|
|
|
16836
16840
|
// ../src/runtime/device_identity_desk.ts
|
|
16837
16841
|
init_define_NOMOS_KERNEL_RELEASE();
|
|
@@ -17750,6 +17754,7 @@ var ReceivingGroupDesk = class {
|
|
|
17750
17754
|
#accounts = /* @__PURE__ */ new Map();
|
|
17751
17755
|
/** D22: device key hash → the workspaces the console reported this key enrolled in (this process's memory, not truth). */
|
|
17752
17756
|
#consoleEnrolments = /* @__PURE__ */ new Map();
|
|
17757
|
+
#preparingWrites = /* @__PURE__ */ new Map();
|
|
17753
17758
|
#sequence = 0;
|
|
17754
17759
|
#internalRequestId = 30000000000n;
|
|
17755
17760
|
constructor(ports) {
|
|
@@ -17789,16 +17794,124 @@ var ReceivingGroupDesk = class {
|
|
|
17789
17794
|
if (head === account.observedHead) return;
|
|
17790
17795
|
this.#tails.set(workspace, { ...account, inFlight: false, attempts: 0, notBefore: 0n });
|
|
17791
17796
|
}
|
|
17792
|
-
/**
|
|
17793
|
-
*
|
|
17797
|
+
/** Only a proven non-admission can enter recovery. Console-enrolled children
|
|
17798
|
+
* share the owning application's route, selected by credential capability and
|
|
17799
|
+
* principal, never by workspace-name guessing or an unverified payload. */
|
|
17794
17800
|
recoverOffer(request, response) {
|
|
17795
|
-
if (!this.#ports.call || request.command.case !== "kernelCall" || request.command.value.credentialUse !== CredentialUse.SESSION || request.command.value.request?.operation.case !== "offer" || request.command.value.request.operation.value.intent.case !== "call"
|
|
17801
|
+
if (!this.#ports.call || request.command.case !== "kernelCall" || request.command.value.credentialUse !== CredentialUse.SESSION || request.command.value.request?.operation.case !== "offer" || request.command.value.request.operation.value.intent.case !== "call") return;
|
|
17802
|
+
const missing = response.outcome.case === "failure" ? response.outcome.value.code === "nomos.authz.signer_enrollment_missing" : response.outcome.case === "offer" && response.outcome.value.outcome.case === "refused" && response.outcome.value.outcome.value.refusal?.code === KernelRefusalCode.FORGED_PRINCIPAL && response.outcome.value.outcome.value.refusal.details?.fields.actor?.kind.case === "text" && response.outcome.value.outcome.value.refusal.details.fields.actor.kind.value === "unenrolled-signer-key";
|
|
17803
|
+
const revoked = response.outcome.case === "failure" && response.outcome.value.code === "nomos.authz.device_key_revoked";
|
|
17804
|
+
if (!missing && !revoked) return;
|
|
17796
17805
|
const binding = this.#ports.binding(request.command.value.session);
|
|
17797
|
-
|
|
17798
|
-
|
|
17806
|
+
if (!binding) return;
|
|
17807
|
+
const enrolled = [...this.#accounts.values()].find((account2) => {
|
|
17808
|
+
const owner = this.#ports.binding(account2.session);
|
|
17809
|
+
return account2.enrolment && owner?.credentialCapability === binding.credentialCapability && owner.principal === binding.principal;
|
|
17810
|
+
});
|
|
17799
17811
|
const copy3 = fromBinary(RuntimeRequestSchema, toBinary(RuntimeRequestSchema, request));
|
|
17812
|
+
if (enrolled?.enrolment) {
|
|
17813
|
+
if (revoked) return this.#writeRefused(binding.workspace, "This device's access has been revoked.");
|
|
17814
|
+
return this.#begin(request, `enrolled-write-${++this.#sequence}`, (workId2) => this.#prepareEnrolledWrite(copy3, binding, enrolled.application, enrolled.enrolment, workId2));
|
|
17815
|
+
}
|
|
17816
|
+
const account = this.#accounts.get(binding.workspace);
|
|
17817
|
+
if (!account) return;
|
|
17800
17818
|
return this.#begin(request, `receiving-group-authoring-${++this.#sequence}`, (workId2) => this.#recoverOffer(copy3, response, account, workId2));
|
|
17801
17819
|
}
|
|
17820
|
+
#writeRefused(workspace, detail, reason = RuntimeRefusalReason.ACCESS_DENIED) {
|
|
17821
|
+
return { case: "refused", value: create(RuntimeRefusalSchema, {
|
|
17822
|
+
reason,
|
|
17823
|
+
workspace,
|
|
17824
|
+
retryable: false,
|
|
17825
|
+
detail
|
|
17826
|
+
}) };
|
|
17827
|
+
}
|
|
17828
|
+
#writeWaiting(workspace, detail) {
|
|
17829
|
+
return { case: "unavailable", value: create(RuntimeUnavailableSchema, {
|
|
17830
|
+
reason: RuntimeUnavailableReason.CREDENTIAL_UNAVAILABLE,
|
|
17831
|
+
workspace,
|
|
17832
|
+
retryable: true,
|
|
17833
|
+
retryAfterMillis: 1e3,
|
|
17834
|
+
detail
|
|
17835
|
+
}) };
|
|
17836
|
+
}
|
|
17837
|
+
*#prepareEnrolledWrite(request, binding, application, route, workId2) {
|
|
17838
|
+
if (request.command.case !== "kernelCall") throw new Error("write preparation lost its call");
|
|
17839
|
+
const command = request.command.value;
|
|
17840
|
+
const principal = binding.principal;
|
|
17841
|
+
const unavailable = () => this.#writeWaiting(
|
|
17842
|
+
binding.workspace,
|
|
17843
|
+
"This device is still being prepared to save changes. Your change has not been saved. Try again when connected."
|
|
17844
|
+
);
|
|
17845
|
+
this.#ports.emit(binding.session, { case: "writePreparation", value: create(WritePreparationSchema, {
|
|
17846
|
+
requestId: command.request.requestId,
|
|
17847
|
+
workspace: binding.workspace
|
|
17848
|
+
}) });
|
|
17849
|
+
const key = JSON.stringify([binding.credentialCapability, principal, binding.workspace]);
|
|
17850
|
+
const shared = this.#preparingWrites.get(key);
|
|
17851
|
+
const deadline = this.#ports.clock.monotonicNanoseconds() + 30000000000n;
|
|
17852
|
+
let wake = 0;
|
|
17853
|
+
if (shared) {
|
|
17854
|
+
while (!shared.settled) {
|
|
17855
|
+
if (this.#ports.clock.monotonicNanoseconds() >= deadline) return unavailable();
|
|
17856
|
+
const receipt = yield { case: "wake", value: create(PeerWakeEffectSchema, {
|
|
17857
|
+
effectId: `${workId2}:join-${++wake}`,
|
|
17858
|
+
delayMillis: 250
|
|
17859
|
+
}) };
|
|
17860
|
+
if (receipt.outcome.case !== "woken") return unavailable();
|
|
17861
|
+
}
|
|
17862
|
+
if (shared.result) return shared.result;
|
|
17863
|
+
} else {
|
|
17864
|
+
const preparation = { settled: false };
|
|
17865
|
+
this.#preparingWrites.set(key, preparation);
|
|
17866
|
+
try {
|
|
17867
|
+
const secret = this.#ports.authorSecretIfPresent(binding.session);
|
|
17868
|
+
if (!secret) return preparation.result = this.#writeRefused(binding.workspace, "Sign in again to set up this device.", RuntimeRefusalReason.INVALID_CREDENTIAL);
|
|
17869
|
+
const keyHash = sha256Hex(this.#ports.deriveSigningPublicKey(secret));
|
|
17870
|
+
let posture = this.#ports.posture(request, binding.session, principal, secret, false);
|
|
17871
|
+
if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
|
|
17872
|
+
return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
|
|
17873
|
+
}
|
|
17874
|
+
if (!posture.enrolledDevice || posture.deviceSignerStatus !== DeviceSignerStatus.ACTIVE) {
|
|
17875
|
+
const enrolled = yield* this.#enrolAtConsole(
|
|
17876
|
+
route,
|
|
17877
|
+
binding,
|
|
17878
|
+
`${application}|${principal}`,
|
|
17879
|
+
principal,
|
|
17880
|
+
keyHash,
|
|
17881
|
+
[binding.workspace],
|
|
17882
|
+
`${workId2}:console`
|
|
17883
|
+
);
|
|
17884
|
+
if (enrolled.case === "deferred") return preparation.result = enrolled.credentialRefused ? this.#writeRefused(binding.workspace, "Sign in again to set up this device.", RuntimeRefusalReason.INVALID_CREDENTIAL) : unavailable();
|
|
17885
|
+
if (!(binding.workspace in enrolled.value.heads)) {
|
|
17886
|
+
return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
|
|
17887
|
+
}
|
|
17888
|
+
while (true) {
|
|
17889
|
+
posture = this.#ports.posture(request, binding.session, principal, secret, false);
|
|
17890
|
+
if (posture.deviceSignerStatus === DeviceSignerStatus.REVOKED) {
|
|
17891
|
+
return preparation.result = this.#writeRefused(binding.workspace, "This device's access has been revoked.");
|
|
17892
|
+
}
|
|
17893
|
+
if (posture.enrolledDevice && posture.deviceSignerStatus === DeviceSignerStatus.ACTIVE) break;
|
|
17894
|
+
if (this.#ports.clock.monotonicNanoseconds() >= deadline) return preparation.result = unavailable();
|
|
17895
|
+
const receipt = yield { case: "wake", value: create(PeerWakeEffectSchema, {
|
|
17896
|
+
effectId: `${workId2}:observe-${++wake}`,
|
|
17897
|
+
delayMillis: 500
|
|
17898
|
+
}) };
|
|
17899
|
+
if (receipt.outcome.case !== "woken") return preparation.result = unavailable();
|
|
17900
|
+
}
|
|
17901
|
+
}
|
|
17902
|
+
} catch (error) {
|
|
17903
|
+
if (error instanceof ReceivingGroupRefusal) {
|
|
17904
|
+
return preparation.result = this.#writeRefused(binding.workspace, "This device could not obtain access to save changes in this workspace.");
|
|
17905
|
+
}
|
|
17906
|
+
preparation.result = unavailable();
|
|
17907
|
+
throw error;
|
|
17908
|
+
} finally {
|
|
17909
|
+
preparation.settled = true;
|
|
17910
|
+
this.#preparingWrites.delete(key);
|
|
17911
|
+
}
|
|
17912
|
+
}
|
|
17913
|
+
return { case: "retried", request, response: this.#ports.call(request, command) };
|
|
17914
|
+
}
|
|
17802
17915
|
*#recoverOffer(request, response, account, workId2) {
|
|
17803
17916
|
const workspace = this.#ports.binding(account.session).workspace;
|
|
17804
17917
|
const deadline = this.#ports.clock.monotonicNanoseconds() + 60000000000n;
|
|
@@ -17866,6 +17979,7 @@ var ReceivingGroupDesk = class {
|
|
|
17866
17979
|
this.#opening.clear();
|
|
17867
17980
|
this.#accounts.clear();
|
|
17868
17981
|
this.#consoleEnrolments.clear();
|
|
17982
|
+
this.#preparingWrites.clear();
|
|
17869
17983
|
}
|
|
17870
17984
|
#begin(request, workId2, procedure) {
|
|
17871
17985
|
const held = {
|
|
@@ -21821,12 +21935,12 @@ var ReplicaFollowController = class {
|
|
|
21821
21935
|
this.#desk.transition(result.workspace, { case: ReplicaFollowEventKind.WentOffline, nowUnixMillis });
|
|
21822
21936
|
return delayUntilDue(this.#desk.get(result.workspace), nowUnixMillis);
|
|
21823
21937
|
}
|
|
21824
|
-
|
|
21825
|
-
|
|
21938
|
+
if (syncNeedsCredentialRefresh(result)) {
|
|
21939
|
+
const offer = result.offerReceipt?.outcome;
|
|
21826
21940
|
const transition = this.#desk.transition(result.workspace, {
|
|
21827
21941
|
case: ReplicaFollowEventKind.CredentialRejected,
|
|
21828
21942
|
nowUnixMillis,
|
|
21829
|
-
failure:
|
|
21943
|
+
failure: (offer?.case === "failure" ? offer.value.message : void 0) || result.pushError?.message || result.discoveryError?.message || "remote requires a refreshed credential"
|
|
21830
21944
|
});
|
|
21831
21945
|
if (transition.effects.some((effect) => effect.case === ReplicaFollowEffectKind.RefreshCredential)) {
|
|
21832
21946
|
return 0;
|
|
@@ -30152,6 +30266,7 @@ var PeerOffice = class {
|
|
|
30152
30266
|
return this.#responses.modelAdoption(request, step);
|
|
30153
30267
|
}
|
|
30154
30268
|
#receivingGroupResponse(request, step) {
|
|
30269
|
+
if (step.case === "refused") return this.#response(request, { case: "refused", value: step.value });
|
|
30155
30270
|
if (step.case === "retried") return this.#birthCustodyResponse(step.request, this.#birthCustody.afterKernelCall(step.request, step.response));
|
|
30156
30271
|
if (step.case === "pending") return this.#response(request, { case: "correspondencePending", value: step.value });
|
|
30157
30272
|
if (step.case === "failure") return this.#failure(request, step.code, step.message);
|
|
@@ -7,7 +7,6 @@ import 'package:nomos_types/nomos_kernel_protocol.dart' as nomos_protocol;
|
|
|
7
7
|
import 'package:nomos_types/nomos_types.dart'
|
|
8
8
|
show
|
|
9
9
|
NomosErrorInfo,
|
|
10
|
-
NomosRefusalReason,
|
|
11
10
|
NomosRefused,
|
|
12
11
|
NomosRuntimeFailure,
|
|
13
12
|
NomosRuntimeFailureKind,
|
|
@@ -46,27 +45,7 @@ final class NmsRuntimeV2Gateway {
|
|
|
46
45
|
throw NomosUnavailable.fromRuntime(response.unavailable);
|
|
47
46
|
}
|
|
48
47
|
if (response.hasRefused()) {
|
|
49
|
-
|
|
50
|
-
throw NomosRefused(
|
|
51
|
-
reason: switch (refused.reason) {
|
|
52
|
-
nomos_protocol.RuntimeRefusalReason
|
|
53
|
-
.RUNTIME_REFUSAL_REASON_INVALID_CREDENTIAL =>
|
|
54
|
-
NomosRefusalReason.invalidCredential,
|
|
55
|
-
nomos_protocol
|
|
56
|
-
.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_ACCESS_DENIED =>
|
|
57
|
-
NomosRefusalReason.accessDenied,
|
|
58
|
-
nomos_protocol
|
|
59
|
-
.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_PLACEMENT_POLICY =>
|
|
60
|
-
NomosRefusalReason.placementPolicy,
|
|
61
|
-
nomos_protocol
|
|
62
|
-
.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_SESSION_UNBOUND =>
|
|
63
|
-
NomosRefusalReason.sessionUnbound,
|
|
64
|
-
_ => NomosRefusalReason.unknown,
|
|
65
|
-
},
|
|
66
|
-
workspace: refused.workspace,
|
|
67
|
-
retryable: refused.retryable,
|
|
68
|
-
detail: refused.detail,
|
|
69
|
-
);
|
|
48
|
+
throw NomosRefused.fromRuntime(response.refused);
|
|
70
49
|
}
|
|
71
50
|
if (response.hasFailure()) {
|
|
72
51
|
final failure = response.failure;
|
|
@@ -16,7 +16,8 @@ import 'package:nomos_peer_host/nomos_peer_host.dart'
|
|
|
16
16
|
NomosProviderCredentialStore,
|
|
17
17
|
NomosSignIn;
|
|
18
18
|
import 'package:nomos_types/nomos_kernel_protocol.dart' as nomos_protocol;
|
|
19
|
-
import 'package:nomos_types/nomos_types.dart'
|
|
19
|
+
import 'package:nomos_types/nomos_types.dart'
|
|
20
|
+
show NomosUnavailable, NomosRefused;
|
|
20
21
|
|
|
21
22
|
import 'console_enrolment.dart';
|
|
22
23
|
import 'console_http_stub.dart' if (dart.library.io) 'console_http_io.dart'
|
|
@@ -648,6 +649,9 @@ mixin NomosRuntimeV2KernelCalls
|
|
|
648
649
|
if (response.hasUnavailable()) {
|
|
649
650
|
throw NomosUnavailable.fromRuntime(response.unavailable);
|
|
650
651
|
}
|
|
652
|
+
if (response.hasRefused()) {
|
|
653
|
+
throw NomosRefused.fromRuntime(response.refused);
|
|
654
|
+
}
|
|
651
655
|
if (!response.hasKernelCall()) {
|
|
652
656
|
throw StateError(
|
|
653
657
|
'Runtime v2 returned ${response.whichOutcome().name} for a kernel call',
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import 'dart:async';
|
|
2
|
+
|
|
3
|
+
/// Presentation of one application action. Completion is the action's local
|
|
4
|
+
/// result; remote durability remains on its existing operation receipt.
|
|
5
|
+
enum NomosWritePhase { running, preparing, completed, failed }
|
|
6
|
+
|
|
7
|
+
final class NomosWriteProgress {
|
|
8
|
+
const NomosWriteProgress(this.phase);
|
|
9
|
+
final NomosWritePhase phase;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/// Optional observation around a generated business action, including any
|
|
13
|
+
/// prerequisite calls it makes. Ordinary unobserved calls recover identically.
|
|
14
|
+
/// This holds no queue, credentials, authority or retry policy. It does not
|
|
15
|
+
/// persist a pending action across process death or cancel an accepted write.
|
|
16
|
+
abstract final class NomosWrite {
|
|
17
|
+
static final Object _observerKey = Object();
|
|
18
|
+
|
|
19
|
+
static Future<T> observe<T>(
|
|
20
|
+
Future<T> Function() action, {
|
|
21
|
+
required void Function(NomosWriteProgress) onProgress,
|
|
22
|
+
}) async {
|
|
23
|
+
void report(NomosWritePhase phase) {
|
|
24
|
+
try {
|
|
25
|
+
onProgress(NomosWriteProgress(phase));
|
|
26
|
+
} catch (_) {
|
|
27
|
+
// Presentation cannot change the operation's outcome.
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
report(NomosWritePhase.running);
|
|
32
|
+
try {
|
|
33
|
+
final result = await runZoned(action, zoneValues: {
|
|
34
|
+
_observerKey: (NomosWriteProgress progress) => report(progress.phase),
|
|
35
|
+
});
|
|
36
|
+
report(NomosWritePhase.completed);
|
|
37
|
+
return result;
|
|
38
|
+
} catch (_) {
|
|
39
|
+
report(NomosWritePhase.failed);
|
|
40
|
+
rethrow;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/// Framework projection seam. Capture before dispatch so an event delivered
|
|
45
|
+
/// outside the calling zone still reaches only its own action's observer.
|
|
46
|
+
static void Function(NomosWriteProgress)? captureObserver() =>
|
|
47
|
+
Zone.current[_observerKey] as void Function(NomosWriteProgress)?;
|
|
48
|
+
}
|
package/dart/pubspec.lock
CHANGED
package/dart/pubspec.yaml
CHANGED
|
@@ -7,7 +7,7 @@ repository: https://github.com/Captain-App/nomos2
|
|
|
7
7
|
description: >-
|
|
8
8
|
Nomos 2 Dart client — generated domain values, intent payloads and application
|
|
9
9
|
lifecycle types over the typed Nomos kernel protocol and USDA custody model.
|
|
10
|
-
version: 0.66.
|
|
10
|
+
version: 0.66.9
|
|
11
11
|
|
|
12
12
|
environment:
|
|
13
13
|
sdk: ^3.5.0
|
|
@@ -18,7 +18,7 @@ dependencies:
|
|
|
18
18
|
# The pure-data core (wire types, offer codec, NomosReads, schema validation, error
|
|
19
19
|
# info). nomos_client depends on and re-exports it, so existing imports are unchanged.
|
|
20
20
|
# For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
|
|
21
|
-
nomos_types: ^0.11.
|
|
21
|
+
nomos_types: ^0.11.3
|
|
22
22
|
fixnum: ^1.1.1
|
|
23
23
|
json_schema: ^5.2.2
|
|
24
24
|
crypto: ^3.0.0
|
|
@@ -3,6 +3,7 @@ import 'dart:convert';
|
|
|
3
3
|
import 'dart:typed_data';
|
|
4
4
|
|
|
5
5
|
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
6
|
+
import 'package:nomos_client/src/write_progress.dart';
|
|
6
7
|
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
7
8
|
import 'package:test/test.dart';
|
|
8
9
|
|
|
@@ -22,6 +23,7 @@ final class _RepairTransport
|
|
|
22
23
|
var syncCalls = 0;
|
|
23
24
|
final syncSessions = <String>[];
|
|
24
25
|
var offerCalls = 0;
|
|
26
|
+
Completer<void>? holdOffer;
|
|
25
27
|
var expireNextSessionOffer = false;
|
|
26
28
|
var refuseSignerEnrollmentOffers = 0;
|
|
27
29
|
var refuseKernelSignerOffers = 0;
|
|
@@ -142,6 +144,14 @@ final class _RepairTransport
|
|
|
142
144
|
}
|
|
143
145
|
if (request.hasOffer()) {
|
|
144
146
|
offerCalls += 1;
|
|
147
|
+
if (holdOffer != null) {
|
|
148
|
+
pushRuntime(protocol.RuntimeEvent(
|
|
149
|
+
writePreparation: protocol.WritePreparation(
|
|
150
|
+
requestId: request.requestId,
|
|
151
|
+
workspace: session,
|
|
152
|
+
)));
|
|
153
|
+
await holdOffer!.future;
|
|
154
|
+
}
|
|
145
155
|
if (refuseKernelSignerOffers > 0) {
|
|
146
156
|
refuseKernelSignerOffers -= 1;
|
|
147
157
|
return protocol.CallResponse(
|
|
@@ -225,6 +235,42 @@ Future<DartReception> _connected(_RepairTransport transport) async {
|
|
|
225
235
|
}
|
|
226
236
|
|
|
227
237
|
void main() {
|
|
238
|
+
test('runtime preparation reaches only its pending generated action observer',
|
|
239
|
+
() async {
|
|
240
|
+
final transport = _RepairTransport()..holdOffer = Completer<void>();
|
|
241
|
+
final bridge = await _connected(transport);
|
|
242
|
+
addTearDown(bridge.dispose);
|
|
243
|
+
final phases = <NomosWritePhase>[];
|
|
244
|
+
final pending = NomosWrite.observe(
|
|
245
|
+
() => bridge
|
|
246
|
+
.session('estate-1')
|
|
247
|
+
.offerGeneratedCallOutcome(call: _estateCall()),
|
|
248
|
+
onProgress: (progress) => phases.add(progress.phase));
|
|
249
|
+
await Future<void>.delayed(Duration.zero);
|
|
250
|
+
expect(phases, [NomosWritePhase.running, NomosWritePhase.preparing]);
|
|
251
|
+
transport.pushRuntime(protocol.RuntimeEvent(
|
|
252
|
+
writePreparation: protocol.WritePreparation(
|
|
253
|
+
requestId: 'another-action',
|
|
254
|
+
workspace: 'estate-1',
|
|
255
|
+
)));
|
|
256
|
+
await Future<void>.delayed(Duration.zero);
|
|
257
|
+
expect(phases.length, 2);
|
|
258
|
+
final requestId = transport.lastCall!.requestId;
|
|
259
|
+
transport.holdOffer!.complete();
|
|
260
|
+
await pending;
|
|
261
|
+
expect(phases.last, NomosWritePhase.completed);
|
|
262
|
+
expect(transport.offerCalls, 1);
|
|
263
|
+
final completed = List<NomosWritePhase>.of(phases);
|
|
264
|
+
transport.pushRuntime(protocol.RuntimeEvent(
|
|
265
|
+
writePreparation: protocol.WritePreparation(
|
|
266
|
+
requestId: requestId,
|
|
267
|
+
workspace: 'estate-1',
|
|
268
|
+
)));
|
|
269
|
+
await Future<void>.delayed(Duration.zero);
|
|
270
|
+
expect(phases, completed,
|
|
271
|
+
reason: 'completed operations detach their observers');
|
|
272
|
+
});
|
|
273
|
+
|
|
228
274
|
test('kernel unenrolled signer refusal repairs the child and retries once',
|
|
229
275
|
() async {
|
|
230
276
|
final transport = _RepairTransport()..refuseKernelSignerOffers = 1;
|
|
@@ -30,6 +30,35 @@ final class _ScriptedKernelCalls extends _ScriptedRuntime
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
void main() {
|
|
33
|
+
test('a refused generated write preserves typed sign-in and access outcomes',
|
|
34
|
+
() async {
|
|
35
|
+
for (final reason in [
|
|
36
|
+
protocol.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_INVALID_CREDENTIAL,
|
|
37
|
+
protocol.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_ACCESS_DENIED,
|
|
38
|
+
]) {
|
|
39
|
+
final runtime =
|
|
40
|
+
_ScriptedKernelCalls((request) => protocol.RuntimeResponse(
|
|
41
|
+
protocolVersion: 2,
|
|
42
|
+
requestId: request.requestId,
|
|
43
|
+
refused: protocol.RuntimeRefusal(
|
|
44
|
+
reason: reason, workspace: 'estate', retryable: false),
|
|
45
|
+
));
|
|
46
|
+
await expectLater(
|
|
47
|
+
runtime.callKernel(
|
|
48
|
+
session: 'estate',
|
|
49
|
+
request: protocol.CallRequest(),
|
|
50
|
+
credentialUse: protocol.CredentialUse.CREDENTIAL_USE_SESSION),
|
|
51
|
+
throwsA(isA<NomosRefused>().having(
|
|
52
|
+
(e) => e.reason,
|
|
53
|
+
'reason',
|
|
54
|
+
reason ==
|
|
55
|
+
protocol.RuntimeRefusalReason
|
|
56
|
+
.RUNTIME_REFUSAL_REASON_INVALID_CREDENTIAL
|
|
57
|
+
? NomosRefusalReason.invalidCredential
|
|
58
|
+
: NomosRefusalReason.accessDenied)));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
33
62
|
test('a kernel call on a copy not ready yet is the typed wait reads sit out',
|
|
34
63
|
() async {
|
|
35
64
|
// A fresh device's first read of a workspace it is still fetching (node, web and in-app
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import 'dart:async';
|
|
2
|
+
import 'package:nomos_client/src/write_progress.dart';
|
|
3
|
+
import 'package:test/test.dart';
|
|
4
|
+
|
|
5
|
+
void main() {
|
|
6
|
+
test('observation spans prerequisites and preserves the result', () async {
|
|
7
|
+
final phases = <NomosWritePhase>[];
|
|
8
|
+
final result = await NomosWrite.observe(() async {
|
|
9
|
+
NomosWrite.captureObserver()!(
|
|
10
|
+
const NomosWriteProgress(NomosWritePhase.preparing));
|
|
11
|
+
await Future<void>.delayed(Duration.zero);
|
|
12
|
+
return 42;
|
|
13
|
+
}, onProgress: (p) => phases.add(p.phase));
|
|
14
|
+
expect(result, 42);
|
|
15
|
+
expect(phases, [
|
|
16
|
+
NomosWritePhase.running,
|
|
17
|
+
NomosWritePhase.preparing,
|
|
18
|
+
NomosWritePhase.completed
|
|
19
|
+
]);
|
|
20
|
+
expect(NomosWrite.captureObserver(), isNull);
|
|
21
|
+
});
|
|
22
|
+
test('concurrent observers do not receive each other\'s progress', () async {
|
|
23
|
+
final first = <NomosWritePhase>[], second = <NomosWritePhase>[];
|
|
24
|
+
final gate = Completer<void>();
|
|
25
|
+
final one = NomosWrite.observe(() async {
|
|
26
|
+
final observer = NomosWrite.captureObserver()!;
|
|
27
|
+
await gate.future;
|
|
28
|
+
observer(const NomosWriteProgress(NomosWritePhase.preparing));
|
|
29
|
+
}, onProgress: (p) => first.add(p.phase));
|
|
30
|
+
await NomosWrite.observe(() async {},
|
|
31
|
+
onProgress: (p) => second.add(p.phase));
|
|
32
|
+
gate.complete();
|
|
33
|
+
await one;
|
|
34
|
+
expect(first, contains(NomosWritePhase.preparing));
|
|
35
|
+
expect(second, [NomosWritePhase.running, NomosWritePhase.completed]);
|
|
36
|
+
});
|
|
37
|
+
test('observer exceptions cannot reject or retry an action', () async {
|
|
38
|
+
var calls = 0;
|
|
39
|
+
expect(
|
|
40
|
+
await NomosWrite.observe(() async {
|
|
41
|
+
calls++;
|
|
42
|
+
return 7;
|
|
43
|
+
}, onProgress: (_) => throw StateError('widget gone')),
|
|
44
|
+
7);
|
|
45
|
+
expect(calls, 1);
|
|
46
|
+
});
|
|
47
|
+
test('typed failure is preserved without retry', () async {
|
|
48
|
+
final failure = StateError('refused');
|
|
49
|
+
final phases = <NomosWritePhase>[];
|
|
50
|
+
await expectLater(
|
|
51
|
+
NomosWrite.observe(() async => throw failure,
|
|
52
|
+
onProgress: (p) => phases.add(p.phase)),
|
|
53
|
+
throwsA(same(failure)));
|
|
54
|
+
expect(phases, [NomosWritePhase.running, NomosWritePhase.failed]);
|
|
55
|
+
});
|
|
56
|
+
}
|
package/dart_types/CHANGELOG.md
CHANGED
|
@@ -617,6 +617,7 @@ enum RuntimeEvent_Event {
|
|
|
617
617
|
localCopyPreserved,
|
|
618
618
|
foreignPlacementIgnored,
|
|
619
619
|
bindingQuarantined,
|
|
620
|
+
writePreparation,
|
|
620
621
|
notSet
|
|
621
622
|
}
|
|
622
623
|
|
|
@@ -644,6 +645,7 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
644
645
|
$5.PreservedLocalCopy? localCopyPreserved,
|
|
645
646
|
$6.ForeignPlacementIgnored? foreignPlacementIgnored,
|
|
646
647
|
$6.QuarantinedBinding? bindingQuarantined,
|
|
648
|
+
WritePreparation? writePreparation,
|
|
647
649
|
}) {
|
|
648
650
|
final result = create();
|
|
649
651
|
if (sequence != null) result.sequence = sequence;
|
|
@@ -675,6 +677,7 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
675
677
|
result.foreignPlacementIgnored = foreignPlacementIgnored;
|
|
676
678
|
if (bindingQuarantined != null)
|
|
677
679
|
result.bindingQuarantined = bindingQuarantined;
|
|
680
|
+
if (writePreparation != null) result.writePreparation = writePreparation;
|
|
678
681
|
return result;
|
|
679
682
|
}
|
|
680
683
|
|
|
@@ -709,6 +712,7 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
709
712
|
27: RuntimeEvent_Event.localCopyPreserved,
|
|
710
713
|
28: RuntimeEvent_Event.foreignPlacementIgnored,
|
|
711
714
|
29: RuntimeEvent_Event.bindingQuarantined,
|
|
715
|
+
30: RuntimeEvent_Event.writePreparation,
|
|
712
716
|
0: RuntimeEvent_Event.notSet
|
|
713
717
|
};
|
|
714
718
|
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
|
@@ -736,7 +740,8 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
736
740
|
26,
|
|
737
741
|
27,
|
|
738
742
|
28,
|
|
739
|
-
29
|
|
743
|
+
29,
|
|
744
|
+
30
|
|
740
745
|
])
|
|
741
746
|
..a<$fixnum.Int64>(
|
|
742
747
|
1, _omitFieldNames ? '' : 'sequence', $pb.PbFieldType.OU6,
|
|
@@ -789,6 +794,8 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
789
794
|
..aOM<$6.QuarantinedBinding>(
|
|
790
795
|
29, _omitFieldNames ? '' : 'bindingQuarantined',
|
|
791
796
|
subBuilder: $6.QuarantinedBinding.create)
|
|
797
|
+
..aOM<WritePreparation>(30, _omitFieldNames ? '' : 'writePreparation',
|
|
798
|
+
subBuilder: WritePreparation.create)
|
|
792
799
|
..hasRequiredFields = false;
|
|
793
800
|
|
|
794
801
|
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
|
@@ -830,6 +837,7 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
830
837
|
@$pb.TagNumber(27)
|
|
831
838
|
@$pb.TagNumber(28)
|
|
832
839
|
@$pb.TagNumber(29)
|
|
840
|
+
@$pb.TagNumber(30)
|
|
833
841
|
RuntimeEvent_Event whichEvent() => _RuntimeEvent_EventByTag[$_whichOneof(0)]!;
|
|
834
842
|
@$pb.TagNumber(10)
|
|
835
843
|
@$pb.TagNumber(11)
|
|
@@ -851,6 +859,7 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
851
859
|
@$pb.TagNumber(27)
|
|
852
860
|
@$pb.TagNumber(28)
|
|
853
861
|
@$pb.TagNumber(29)
|
|
862
|
+
@$pb.TagNumber(30)
|
|
854
863
|
void clearEvent() => $_clearField($_whichOneof(0));
|
|
855
864
|
|
|
856
865
|
@$pb.TagNumber(1)
|
|
@@ -1099,6 +1108,17 @@ class RuntimeEvent extends $pb.GeneratedMessage {
|
|
|
1099
1108
|
void clearBindingQuarantined() => $_clearField(29);
|
|
1100
1109
|
@$pb.TagNumber(29)
|
|
1101
1110
|
$6.QuarantinedBinding ensureBindingQuarantined() => $_ensure(21);
|
|
1111
|
+
|
|
1112
|
+
@$pb.TagNumber(30)
|
|
1113
|
+
WritePreparation get writePreparation => $_getN(22);
|
|
1114
|
+
@$pb.TagNumber(30)
|
|
1115
|
+
set writePreparation(WritePreparation value) => $_setField(30, value);
|
|
1116
|
+
@$pb.TagNumber(30)
|
|
1117
|
+
$core.bool hasWritePreparation() => $_has(22);
|
|
1118
|
+
@$pb.TagNumber(30)
|
|
1119
|
+
void clearWritePreparation() => $_clearField(30);
|
|
1120
|
+
@$pb.TagNumber(30)
|
|
1121
|
+
WritePreparation ensureWritePreparation() => $_ensure(22);
|
|
1102
1122
|
}
|
|
1103
1123
|
|
|
1104
1124
|
/// Application-wide (no session): the replica follows this peer keeps up with in the background.
|
|
@@ -2225,6 +2245,75 @@ class TransferProgress extends $pb.GeneratedMessage {
|
|
|
2225
2245
|
void clearKind() => $_clearField(3);
|
|
2226
2246
|
}
|
|
2227
2247
|
|
|
2248
|
+
/// Transient observation for one refused, not-yet-admitted generated call. The
|
|
2249
|
+
/// office owns recovery; observing this event is never required for correctness.
|
|
2250
|
+
class WritePreparation extends $pb.GeneratedMessage {
|
|
2251
|
+
factory WritePreparation({
|
|
2252
|
+
$core.String? requestId,
|
|
2253
|
+
$core.String? workspace,
|
|
2254
|
+
}) {
|
|
2255
|
+
final result = create();
|
|
2256
|
+
if (requestId != null) result.requestId = requestId;
|
|
2257
|
+
if (workspace != null) result.workspace = workspace;
|
|
2258
|
+
return result;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
WritePreparation._();
|
|
2262
|
+
|
|
2263
|
+
factory WritePreparation.fromBuffer($core.List<$core.int> data,
|
|
2264
|
+
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
|
2265
|
+
create()..mergeFromBuffer(data, registry);
|
|
2266
|
+
factory WritePreparation.fromJson($core.String json,
|
|
2267
|
+
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
|
2268
|
+
create()..mergeFromJson(json, registry);
|
|
2269
|
+
|
|
2270
|
+
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
|
2271
|
+
_omitMessageNames ? '' : 'WritePreparation',
|
|
2272
|
+
package:
|
|
2273
|
+
const $pb.PackageName(_omitMessageNames ? '' : 'nomos.runtime.v2'),
|
|
2274
|
+
createEmptyInstance: create)
|
|
2275
|
+
..aOS(1, _omitFieldNames ? '' : 'requestId')
|
|
2276
|
+
..aOS(2, _omitFieldNames ? '' : 'workspace')
|
|
2277
|
+
..hasRequiredFields = false;
|
|
2278
|
+
|
|
2279
|
+
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
|
2280
|
+
WritePreparation clone() => deepCopy();
|
|
2281
|
+
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
|
2282
|
+
WritePreparation copyWith(void Function(WritePreparation) updates) =>
|
|
2283
|
+
super.copyWith((message) => updates(message as WritePreparation))
|
|
2284
|
+
as WritePreparation;
|
|
2285
|
+
|
|
2286
|
+
@$core.override
|
|
2287
|
+
$pb.BuilderInfo get info_ => _i;
|
|
2288
|
+
|
|
2289
|
+
@$core.pragma('dart2js:noInline')
|
|
2290
|
+
static WritePreparation create() => WritePreparation._();
|
|
2291
|
+
@$core.override
|
|
2292
|
+
WritePreparation createEmptyInstance() => create();
|
|
2293
|
+
@$core.pragma('dart2js:noInline')
|
|
2294
|
+
static WritePreparation getDefault() => _defaultInstance ??=
|
|
2295
|
+
$pb.GeneratedMessage.$_defaultFor<WritePreparation>(create);
|
|
2296
|
+
static WritePreparation? _defaultInstance;
|
|
2297
|
+
|
|
2298
|
+
@$pb.TagNumber(1)
|
|
2299
|
+
$core.String get requestId => $_getSZ(0);
|
|
2300
|
+
@$pb.TagNumber(1)
|
|
2301
|
+
set requestId($core.String value) => $_setString(0, value);
|
|
2302
|
+
@$pb.TagNumber(1)
|
|
2303
|
+
$core.bool hasRequestId() => $_has(0);
|
|
2304
|
+
@$pb.TagNumber(1)
|
|
2305
|
+
void clearRequestId() => $_clearField(1);
|
|
2306
|
+
|
|
2307
|
+
@$pb.TagNumber(2)
|
|
2308
|
+
$core.String get workspace => $_getSZ(1);
|
|
2309
|
+
@$pb.TagNumber(2)
|
|
2310
|
+
set workspace($core.String value) => $_setString(1, value);
|
|
2311
|
+
@$pb.TagNumber(2)
|
|
2312
|
+
$core.bool hasWorkspace() => $_has(1);
|
|
2313
|
+
@$pb.TagNumber(2)
|
|
2314
|
+
void clearWorkspace() => $_clearField(2);
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2228
2317
|
const $core.bool _omitFieldNames =
|
|
2229
2318
|
$core.bool.fromEnvironment('protobuf.omit_field_names');
|
|
2230
2319
|
const $core.bool _omitMessageNames =
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
library;
|
|
7
7
|
|
|
8
8
|
import 'proto/nomos/runtime/v2/observability_desk.pb.dart'
|
|
9
|
-
show RuntimeUnavailable;
|
|
9
|
+
show RuntimeUnavailable, RuntimeRefusal;
|
|
10
10
|
import 'proto/nomos/runtime/v2/observability_desk.pbenum.dart'
|
|
11
|
-
show RuntimeUnavailableReason;
|
|
11
|
+
show RuntimeUnavailableReason, RuntimeRefusalReason;
|
|
12
12
|
|
|
13
13
|
enum NomosUnavailableReason {
|
|
14
14
|
remoteOnlyOffline,
|
|
@@ -39,35 +39,33 @@ final class NomosUnavailable implements Exception {
|
|
|
39
39
|
final String detail;
|
|
40
40
|
|
|
41
41
|
/// The one translation of the generated `unavailable` arm, for every transport.
|
|
42
|
-
factory NomosUnavailable.fromRuntime(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
detail: unavailable.detail,
|
|
70
|
-
);
|
|
42
|
+
factory NomosUnavailable.fromRuntime(
|
|
43
|
+
RuntimeUnavailable unavailable,
|
|
44
|
+
) => NomosUnavailable(
|
|
45
|
+
reason: switch (unavailable.reason) {
|
|
46
|
+
RuntimeUnavailableReason.RUNTIME_UNAVAILABLE_REASON_REMOTE_ONLY_OFFLINE =>
|
|
47
|
+
NomosUnavailableReason.remoteOnlyOffline,
|
|
48
|
+
RuntimeUnavailableReason.RUNTIME_UNAVAILABLE_REASON_REMOTE_UNREACHABLE =>
|
|
49
|
+
NomosUnavailableReason.remoteUnreachable,
|
|
50
|
+
RuntimeUnavailableReason.RUNTIME_UNAVAILABLE_REASON_REMOTE_TIMEOUT =>
|
|
51
|
+
NomosUnavailableReason.remoteTimeout,
|
|
52
|
+
RuntimeUnavailableReason
|
|
53
|
+
.RUNTIME_UNAVAILABLE_REASON_LOCAL_REPLICA_NOT_READY =>
|
|
54
|
+
NomosUnavailableReason.localReplicaNotReady,
|
|
55
|
+
RuntimeUnavailableReason
|
|
56
|
+
.RUNTIME_UNAVAILABLE_REASON_CREDENTIAL_UNAVAILABLE =>
|
|
57
|
+
NomosUnavailableReason.credentialUnavailable,
|
|
58
|
+
RuntimeUnavailableReason.RUNTIME_UNAVAILABLE_REASON_WORKSPACE_OPENING =>
|
|
59
|
+
NomosUnavailableReason.workspaceOpening,
|
|
60
|
+
_ => NomosUnavailableReason.unknown,
|
|
61
|
+
},
|
|
62
|
+
workspace: unavailable.workspace,
|
|
63
|
+
retryable: unavailable.retryable,
|
|
64
|
+
retryAfter: unavailable.hasRetryAfterMillis()
|
|
65
|
+
? Duration(milliseconds: unavailable.retryAfterMillis)
|
|
66
|
+
: null,
|
|
67
|
+
detail: unavailable.detail,
|
|
68
|
+
);
|
|
71
69
|
|
|
72
70
|
@override
|
|
73
71
|
String toString() =>
|
|
@@ -91,6 +89,23 @@ final class NomosRefused implements Exception {
|
|
|
91
89
|
this.detail = '',
|
|
92
90
|
});
|
|
93
91
|
|
|
92
|
+
factory NomosRefused.fromRuntime(RuntimeRefusal refused) => NomosRefused(
|
|
93
|
+
reason: switch (refused.reason) {
|
|
94
|
+
RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_INVALID_CREDENTIAL =>
|
|
95
|
+
NomosRefusalReason.invalidCredential,
|
|
96
|
+
RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_ACCESS_DENIED =>
|
|
97
|
+
NomosRefusalReason.accessDenied,
|
|
98
|
+
RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_PLACEMENT_POLICY =>
|
|
99
|
+
NomosRefusalReason.placementPolicy,
|
|
100
|
+
RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_SESSION_UNBOUND =>
|
|
101
|
+
NomosRefusalReason.sessionUnbound,
|
|
102
|
+
_ => NomosRefusalReason.unknown,
|
|
103
|
+
},
|
|
104
|
+
workspace: refused.workspace,
|
|
105
|
+
retryable: refused.retryable,
|
|
106
|
+
detail: refused.detail,
|
|
107
|
+
);
|
|
108
|
+
|
|
94
109
|
final NomosRefusalReason reason;
|
|
95
110
|
final String workspace;
|
|
96
111
|
final bool retryable;
|
package/dart_types/pubspec.yaml
CHANGED
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
|
|
10
10
|
no runtime. Typed protobuf and USDA boundary values plus the offer codec,
|
|
11
11
|
reactive read engine, schema validation, and data-only error/trace types.
|
|
12
|
-
version: 0.11.
|
|
12
|
+
version: 0.11.3
|
|
13
13
|
|
|
14
14
|
environment:
|
|
15
15
|
sdk: ^3.5.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.111.
|
|
3
|
+
"version": "0.111.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"test": "vitest run"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@githolon/runtime": "^0.111.
|
|
75
|
+
"@githolon/runtime": "^0.111.1",
|
|
76
76
|
"@bufbuild/protobuf": "^2.13.0",
|
|
77
77
|
"@bufbuild/protoc-gen-es": "^2.13.0",
|
|
78
78
|
"esbuild": "0.24.2",
|
|
@@ -1906,6 +1906,7 @@ export function generateDartApplication(
|
|
|
1906
1906
|
return [
|
|
1907
1907
|
`// AUTO-GENERATED by nomos-compile — the tenant application surface for "${domain}".`,
|
|
1908
1908
|
`// Business facts in, business records out. Runtime lifecycle is deliberately absent.`,
|
|
1909
|
+
`export 'package:nomos_client/src/write_progress.dart' show NomosWrite, NomosWriteProgress, NomosWritePhase;`,
|
|
1909
1910
|
...((mod.workspaceInvariants ?? []).some(rule => rule.refusal) ? [
|
|
1910
1911
|
`export 'package:nomos_types/nomos_types.dart' show AdmissionDecision, Admitted, DomainRefused, FrameworkRefused, UnsupportedRefusalContract, NomosDomainRefusalEvidence, KernelRefusalCode;`,
|
|
1911
1912
|
] : []),
|
|
@@ -2540,12 +2540,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
|
|
|
2540
2540
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
2541
2541
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
2542
2542
|
// the pendingConflicts read rows.
|
|
2543
|
-
const NOMOS_TYPES_DEP = "^0.11.
|
|
2543
|
+
const NOMOS_TYPES_DEP = "^0.11.3";
|
|
2544
2544
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
2545
2545
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
2546
2546
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
2547
|
-
const NOMOS_CLIENT_DEP = "^0.66.
|
|
2548
|
-
const NOMOS_FLUTTER_DEP = "^0.65.
|
|
2547
|
+
const NOMOS_CLIENT_DEP = "^0.66.9";
|
|
2548
|
+
const NOMOS_FLUTTER_DEP = "^0.65.13";
|
|
2549
2549
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in the Dart and Flutter
|
|
2550
2550
|
// package pubspecs — a release without this bump fails the suite, so tenants never
|
|
2551
2551
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -3854,6 +3854,7 @@ function emitDartPackages(
|
|
|
3854
3854
|
"",
|
|
3855
3855
|
`export 'package:${packages.types}/${genRel}/${businessSharedFile}';`,
|
|
3856
3856
|
`export 'package:nomos_client/src/workspace_open_progress.dart' show ApplicationWorkspaceOpenProgress;`,
|
|
3857
|
+
`export 'package:nomos_client/src/write_progress.dart' show NomosWrite, NomosWriteProgress, NomosWritePhase;`,
|
|
3857
3858
|
`export 'package:nomos_types/nomos_types.dart' show CustodyError, CustodyPhase, CustodySource, NomosRecommendedAction;`,
|
|
3858
3859
|
...tenantTypesExportKeys
|
|
3859
3860
|
.map((file) => {
|