@ottochain/sdk 2.2.2 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -3,32 +3,41 @@
|
|
|
3
3
|
* Normalize OttoChain Messages for Signing
|
|
4
4
|
*
|
|
5
5
|
* Converts OttoChain message objects to the wire format expected by the
|
|
6
|
-
* Scala metagraph.
|
|
7
|
-
*
|
|
8
|
-
* produces on the Scala side.
|
|
6
|
+
* Scala metagraph. Metakit's JsonBinaryCodec (used by OttoChain for data
|
|
7
|
+
* transaction signing) canonicalizes JSON with dropNullValues = true.
|
|
9
8
|
*
|
|
10
|
-
* This is
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* JSON won't match and signature verification will fail.
|
|
9
|
+
* NOTE: This is Metakit's codec, NOT tessellation's JsonSerializer (which
|
|
10
|
+
* uses Brotli compression for snapshots/consensus — a different layer).
|
|
11
|
+
* Different layers use different byte-sequence encoders.
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* Because Metakit drops null fields during canonicalization, the canonical
|
|
14
|
+
* JSON used for signature verification **omits** null fields entirely.
|
|
15
|
+
* If the TypeScript client includes explicit nulls (e.g., `"metadata": null`),
|
|
16
|
+
* the canonical form won't match and signature verification will fail.
|
|
17
|
+
*
|
|
18
|
+
* Schema mapping (Scala → TypeScript wire format):
|
|
19
|
+
* - `Option[A] = None` → field OMITTED (not null, not undefined)
|
|
17
20
|
* - `Option[A] = Some(v)` → `v`
|
|
18
|
-
* - `List.empty` → `[]`
|
|
21
|
+
* - `List.empty` / `Set.empty` → `[]`
|
|
19
22
|
* - `Map.empty` → `{}`
|
|
23
|
+
* - `Boolean = false` → `false` (always include, not a null/Option)
|
|
20
24
|
*/
|
|
21
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
26
|
exports.normalizeMessage = exports.normalizeArchiveStateMachine = exports.normalizeTransitionStateMachine = exports.normalizeCreateStateMachine = void 0;
|
|
23
27
|
/**
|
|
24
|
-
* Normalize a State object for wire format
|
|
28
|
+
* Normalize a State object for wire format.
|
|
29
|
+
* State: id (required), isFinal (default false), metadata (Option = None)
|
|
30
|
+
* Omit metadata when null/undefined (dropNullValues).
|
|
25
31
|
*/
|
|
26
32
|
function normalizeState(state) {
|
|
27
|
-
|
|
33
|
+
const result = {
|
|
28
34
|
id: state.id,
|
|
29
35
|
isFinal: state.isFinal ?? false,
|
|
30
|
-
metadata: state.metadata ?? null,
|
|
31
36
|
};
|
|
37
|
+
if (state.metadata != null) {
|
|
38
|
+
result.metadata = state.metadata;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
32
41
|
}
|
|
33
42
|
/**
|
|
34
43
|
* Normalize a Transition object for wire format
|
|
@@ -54,8 +63,21 @@ function normalizeTransition(t) {
|
|
|
54
63
|
dependencies: t.dependencies ?? [],
|
|
55
64
|
};
|
|
56
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if a value looks like FiberAppMetadata (has 'name' and 'app' fields).
|
|
68
|
+
* These TypeScript-only fields should be stripped before sending to metagraph.
|
|
69
|
+
*/
|
|
70
|
+
function isFiberAppMetadata(value) {
|
|
71
|
+
return (typeof value === 'object' &&
|
|
72
|
+
value !== null &&
|
|
73
|
+
'name' in value &&
|
|
74
|
+
'app' in value);
|
|
75
|
+
}
|
|
57
76
|
/**
|
|
58
77
|
* Normalize a StateMachineDefinition for wire format
|
|
78
|
+
*
|
|
79
|
+
* Strips FiberAppMetadata from the definition — the Scala schema expects
|
|
80
|
+
* `metadata: Option[Json] = None`, not the TypeScript app metadata object.
|
|
59
81
|
*/
|
|
60
82
|
function normalizeDefinition(def) {
|
|
61
83
|
const states = def.states;
|
|
@@ -66,41 +88,55 @@ function normalizeDefinition(def) {
|
|
|
66
88
|
}
|
|
67
89
|
}
|
|
68
90
|
const transitions = def.transitions ?? [];
|
|
69
|
-
|
|
91
|
+
// Strip FiberAppMetadata if present — it's TypeScript-only, not part of wire format.
|
|
92
|
+
// Omit metadata entirely when null/FiberAppMetadata (dropNullValues = true on Scala side).
|
|
93
|
+
const wireMetadata = isFiberAppMetadata(def.metadata) ? undefined : def.metadata;
|
|
94
|
+
const result = {
|
|
70
95
|
states: normalizedStates,
|
|
71
96
|
initialState: def.initialState,
|
|
72
97
|
transitions: transitions.map(normalizeTransition),
|
|
73
|
-
metadata: def.metadata ?? null,
|
|
74
98
|
};
|
|
99
|
+
if (wireMetadata != null) {
|
|
100
|
+
result.metadata = wireMetadata;
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
75
103
|
}
|
|
76
104
|
/**
|
|
77
105
|
* Normalize a CreateStateMachine message for wire format
|
|
78
106
|
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* -
|
|
84
|
-
* -
|
|
107
|
+
* Metakit's JsonBinaryCodec uses dropNullValues = true for canonicalization.
|
|
108
|
+
* Optional fields at their defaults must be OMITTED (not set to null)
|
|
109
|
+
* to match the canonical JSON used for signature verification.
|
|
110
|
+
*
|
|
111
|
+
* - definition.metadata → OMITTED when absent/FiberAppMetadata
|
|
112
|
+
* - definition.states[*].metadata → OMITTED when absent
|
|
113
|
+
* - definition.transitions[*].dependencies → [] (Set.empty default, always included)
|
|
114
|
+
* - parentFiberId → OMITTED when absent (Option[UUID] = None)
|
|
115
|
+
* - participants → OMITTED when absent (Option[Set[Address]] = None)
|
|
85
116
|
*
|
|
86
117
|
* @example
|
|
87
118
|
* ```typescript
|
|
88
119
|
* const message = normalizeCreateStateMachine({
|
|
89
120
|
* fiberId: '...',
|
|
90
|
-
* definition: { states: { INIT: { id:
|
|
121
|
+
* definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
|
|
91
122
|
* initialData: {}
|
|
92
123
|
* });
|
|
93
|
-
* //
|
|
124
|
+
* // Optional fields are absent (not null): no parentFiberId, no metadata, etc.
|
|
94
125
|
* ```
|
|
95
126
|
*/
|
|
96
127
|
function normalizeCreateStateMachine(msg) {
|
|
97
|
-
|
|
128
|
+
const result = {
|
|
98
129
|
fiberId: msg.fiberId,
|
|
99
130
|
definition: normalizeDefinition(msg.definition),
|
|
100
131
|
initialData: msg.initialData ?? {},
|
|
101
|
-
parentFiberId: msg.parentFiberId ?? null,
|
|
102
|
-
participants: msg.participants ?? null,
|
|
103
132
|
};
|
|
133
|
+
if (msg.parentFiberId != null) {
|
|
134
|
+
result.parentFiberId = msg.parentFiberId;
|
|
135
|
+
}
|
|
136
|
+
if (msg.participants != null) {
|
|
137
|
+
result.participants = msg.participants;
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
104
140
|
}
|
|
105
141
|
exports.normalizeCreateStateMachine = normalizeCreateStateMachine;
|
|
106
142
|
/**
|
|
@@ -2,30 +2,39 @@
|
|
|
2
2
|
* Normalize OttoChain Messages for Signing
|
|
3
3
|
*
|
|
4
4
|
* Converts OttoChain message objects to the wire format expected by the
|
|
5
|
-
* Scala metagraph.
|
|
6
|
-
*
|
|
7
|
-
* produces on the Scala side.
|
|
5
|
+
* Scala metagraph. Metakit's JsonBinaryCodec (used by OttoChain for data
|
|
6
|
+
* transaction signing) canonicalizes JSON with dropNullValues = true.
|
|
8
7
|
*
|
|
9
|
-
* This is
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* JSON won't match and signature verification will fail.
|
|
8
|
+
* NOTE: This is Metakit's codec, NOT tessellation's JsonSerializer (which
|
|
9
|
+
* uses Brotli compression for snapshots/consensus — a different layer).
|
|
10
|
+
* Different layers use different byte-sequence encoders.
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* Because Metakit drops null fields during canonicalization, the canonical
|
|
13
|
+
* JSON used for signature verification **omits** null fields entirely.
|
|
14
|
+
* If the TypeScript client includes explicit nulls (e.g., `"metadata": null`),
|
|
15
|
+
* the canonical form won't match and signature verification will fail.
|
|
16
|
+
*
|
|
17
|
+
* Schema mapping (Scala → TypeScript wire format):
|
|
18
|
+
* - `Option[A] = None` → field OMITTED (not null, not undefined)
|
|
16
19
|
* - `Option[A] = Some(v)` → `v`
|
|
17
|
-
* - `List.empty` → `[]`
|
|
20
|
+
* - `List.empty` / `Set.empty` → `[]`
|
|
18
21
|
* - `Map.empty` → `{}`
|
|
22
|
+
* - `Boolean = false` → `false` (always include, not a null/Option)
|
|
19
23
|
*/
|
|
20
24
|
/**
|
|
21
|
-
* Normalize a State object for wire format
|
|
25
|
+
* Normalize a State object for wire format.
|
|
26
|
+
* State: id (required), isFinal (default false), metadata (Option = None)
|
|
27
|
+
* Omit metadata when null/undefined (dropNullValues).
|
|
22
28
|
*/
|
|
23
29
|
function normalizeState(state) {
|
|
24
|
-
|
|
30
|
+
const result = {
|
|
25
31
|
id: state.id,
|
|
26
32
|
isFinal: state.isFinal ?? false,
|
|
27
|
-
metadata: state.metadata ?? null,
|
|
28
33
|
};
|
|
34
|
+
if (state.metadata != null) {
|
|
35
|
+
result.metadata = state.metadata;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
29
38
|
}
|
|
30
39
|
/**
|
|
31
40
|
* Normalize a Transition object for wire format
|
|
@@ -51,8 +60,21 @@ function normalizeTransition(t) {
|
|
|
51
60
|
dependencies: t.dependencies ?? [],
|
|
52
61
|
};
|
|
53
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if a value looks like FiberAppMetadata (has 'name' and 'app' fields).
|
|
65
|
+
* These TypeScript-only fields should be stripped before sending to metagraph.
|
|
66
|
+
*/
|
|
67
|
+
function isFiberAppMetadata(value) {
|
|
68
|
+
return (typeof value === 'object' &&
|
|
69
|
+
value !== null &&
|
|
70
|
+
'name' in value &&
|
|
71
|
+
'app' in value);
|
|
72
|
+
}
|
|
54
73
|
/**
|
|
55
74
|
* Normalize a StateMachineDefinition for wire format
|
|
75
|
+
*
|
|
76
|
+
* Strips FiberAppMetadata from the definition — the Scala schema expects
|
|
77
|
+
* `metadata: Option[Json] = None`, not the TypeScript app metadata object.
|
|
56
78
|
*/
|
|
57
79
|
function normalizeDefinition(def) {
|
|
58
80
|
const states = def.states;
|
|
@@ -63,41 +85,55 @@ function normalizeDefinition(def) {
|
|
|
63
85
|
}
|
|
64
86
|
}
|
|
65
87
|
const transitions = def.transitions ?? [];
|
|
66
|
-
|
|
88
|
+
// Strip FiberAppMetadata if present — it's TypeScript-only, not part of wire format.
|
|
89
|
+
// Omit metadata entirely when null/FiberAppMetadata (dropNullValues = true on Scala side).
|
|
90
|
+
const wireMetadata = isFiberAppMetadata(def.metadata) ? undefined : def.metadata;
|
|
91
|
+
const result = {
|
|
67
92
|
states: normalizedStates,
|
|
68
93
|
initialState: def.initialState,
|
|
69
94
|
transitions: transitions.map(normalizeTransition),
|
|
70
|
-
metadata: def.metadata ?? null,
|
|
71
95
|
};
|
|
96
|
+
if (wireMetadata != null) {
|
|
97
|
+
result.metadata = wireMetadata;
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
72
100
|
}
|
|
73
101
|
/**
|
|
74
102
|
* Normalize a CreateStateMachine message for wire format
|
|
75
103
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* -
|
|
81
|
-
* -
|
|
104
|
+
* Metakit's JsonBinaryCodec uses dropNullValues = true for canonicalization.
|
|
105
|
+
* Optional fields at their defaults must be OMITTED (not set to null)
|
|
106
|
+
* to match the canonical JSON used for signature verification.
|
|
107
|
+
*
|
|
108
|
+
* - definition.metadata → OMITTED when absent/FiberAppMetadata
|
|
109
|
+
* - definition.states[*].metadata → OMITTED when absent
|
|
110
|
+
* - definition.transitions[*].dependencies → [] (Set.empty default, always included)
|
|
111
|
+
* - parentFiberId → OMITTED when absent (Option[UUID] = None)
|
|
112
|
+
* - participants → OMITTED when absent (Option[Set[Address]] = None)
|
|
82
113
|
*
|
|
83
114
|
* @example
|
|
84
115
|
* ```typescript
|
|
85
116
|
* const message = normalizeCreateStateMachine({
|
|
86
117
|
* fiberId: '...',
|
|
87
|
-
* definition: { states: { INIT: { id:
|
|
118
|
+
* definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
|
|
88
119
|
* initialData: {}
|
|
89
120
|
* });
|
|
90
|
-
* //
|
|
121
|
+
* // Optional fields are absent (not null): no parentFiberId, no metadata, etc.
|
|
91
122
|
* ```
|
|
92
123
|
*/
|
|
93
124
|
export function normalizeCreateStateMachine(msg) {
|
|
94
|
-
|
|
125
|
+
const result = {
|
|
95
126
|
fiberId: msg.fiberId,
|
|
96
127
|
definition: normalizeDefinition(msg.definition),
|
|
97
128
|
initialData: msg.initialData ?? {},
|
|
98
|
-
parentFiberId: msg.parentFiberId ?? null,
|
|
99
|
-
participants: msg.participants ?? null,
|
|
100
129
|
};
|
|
130
|
+
if (msg.parentFiberId != null) {
|
|
131
|
+
result.parentFiberId = msg.parentFiberId;
|
|
132
|
+
}
|
|
133
|
+
if (msg.participants != null) {
|
|
134
|
+
result.participants = msg.participants;
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
101
137
|
}
|
|
102
138
|
/**
|
|
103
139
|
* Normalize a TransitionStateMachine message for wire format
|
|
@@ -2,39 +2,46 @@
|
|
|
2
2
|
* Normalize OttoChain Messages for Signing
|
|
3
3
|
*
|
|
4
4
|
* Converts OttoChain message objects to the wire format expected by the
|
|
5
|
-
* Scala metagraph.
|
|
6
|
-
*
|
|
7
|
-
* produces on the Scala side.
|
|
5
|
+
* Scala metagraph. Metakit's JsonBinaryCodec (used by OttoChain for data
|
|
6
|
+
* transaction signing) canonicalizes JSON with dropNullValues = true.
|
|
8
7
|
*
|
|
9
|
-
* This is
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* JSON won't match and signature verification will fail.
|
|
8
|
+
* NOTE: This is Metakit's codec, NOT tessellation's JsonSerializer (which
|
|
9
|
+
* uses Brotli compression for snapshots/consensus — a different layer).
|
|
10
|
+
* Different layers use different byte-sequence encoders.
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* Because Metakit drops null fields during canonicalization, the canonical
|
|
13
|
+
* JSON used for signature verification **omits** null fields entirely.
|
|
14
|
+
* If the TypeScript client includes explicit nulls (e.g., `"metadata": null`),
|
|
15
|
+
* the canonical form won't match and signature verification will fail.
|
|
16
|
+
*
|
|
17
|
+
* Schema mapping (Scala → TypeScript wire format):
|
|
18
|
+
* - `Option[A] = None` → field OMITTED (not null, not undefined)
|
|
16
19
|
* - `Option[A] = Some(v)` → `v`
|
|
17
|
-
* - `List.empty` → `[]`
|
|
20
|
+
* - `List.empty` / `Set.empty` → `[]`
|
|
18
21
|
* - `Map.empty` → `{}`
|
|
22
|
+
* - `Boolean = false` → `false` (always include, not a null/Option)
|
|
19
23
|
*/
|
|
20
24
|
/**
|
|
21
25
|
* Normalize a CreateStateMachine message for wire format
|
|
22
26
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* -
|
|
28
|
-
* -
|
|
27
|
+
* Metakit's JsonBinaryCodec uses dropNullValues = true for canonicalization.
|
|
28
|
+
* Optional fields at their defaults must be OMITTED (not set to null)
|
|
29
|
+
* to match the canonical JSON used for signature verification.
|
|
30
|
+
*
|
|
31
|
+
* - definition.metadata → OMITTED when absent/FiberAppMetadata
|
|
32
|
+
* - definition.states[*].metadata → OMITTED when absent
|
|
33
|
+
* - definition.transitions[*].dependencies → [] (Set.empty default, always included)
|
|
34
|
+
* - parentFiberId → OMITTED when absent (Option[UUID] = None)
|
|
35
|
+
* - participants → OMITTED when absent (Option[Set[Address]] = None)
|
|
29
36
|
*
|
|
30
37
|
* @example
|
|
31
38
|
* ```typescript
|
|
32
39
|
* const message = normalizeCreateStateMachine({
|
|
33
40
|
* fiberId: '...',
|
|
34
|
-
* definition: { states: { INIT: { id:
|
|
41
|
+
* definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
|
|
35
42
|
* initialData: {}
|
|
36
43
|
* });
|
|
37
|
-
* //
|
|
44
|
+
* // Optional fields are absent (not null): no parentFiberId, no metadata, etc.
|
|
38
45
|
* ```
|
|
39
46
|
*/
|
|
40
47
|
export declare function normalizeCreateStateMachine(msg: Record<string, unknown>): Record<string, unknown>;
|
package/package.json
CHANGED