@ottochain/sdk 2.2.3 → 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. Specifically, ensures all `Option[A]=None` fields are
7
- * present as explicit `null` values, matching what circe's magnolia encoder
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 necessary because metakit's `JsonBinaryCodec.deriveDataUpdate`
11
- * (rc.8) canonicalizes the circe-encoded JSON **including null fields**.
12
- * If the TypeScript client omits optional fields (undefined), the canonical
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
- * Schema mapping (Scala TypeScript):
16
- * - `Option[A] = None` `null` (must be explicit, not undefined/absent)
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
- return {
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
@@ -80,43 +89,54 @@ function normalizeDefinition(def) {
80
89
  }
81
90
  const transitions = def.transitions ?? [];
82
91
  // Strip FiberAppMetadata if present — it's TypeScript-only, not part of wire format.
83
- // The Scala schema has `metadata: Option[Json] = None`, so use null for wire format.
84
- const wireMetadata = isFiberAppMetadata(def.metadata) ? null : (def.metadata ?? null);
85
- return {
92
+ // Omit metadata entirely when null/FiberAppMetadata (dropNullValues = true on Scala side).
93
+ const wireMetadata = isFiberAppMetadata(def.metadata) ? undefined : def.metadata;
94
+ const result = {
86
95
  states: normalizedStates,
87
96
  initialState: def.initialState,
88
97
  transitions: transitions.map(normalizeTransition),
89
- metadata: wireMetadata,
90
98
  };
99
+ if (wireMetadata != null) {
100
+ result.metadata = wireMetadata;
101
+ }
102
+ return result;
91
103
  }
92
104
  /**
93
105
  * Normalize a CreateStateMachine message for wire format
94
106
  *
95
- * Ensures all Option/default fields are explicit in wire format:
96
- * - definition.metadata null when absent
97
- * - definition.states[*].metadata null when absent
98
- * - definition.transitions[*].dependencies → [] when absent
99
- * - parentFiberIdnull when absent
100
- * - participantsnull when absent (Optional Set[Address] for multi-party signing)
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.metadataOMITTED when absent/FiberAppMetadata
112
+ * - definition.states[*].metadataOMITTED 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)
101
116
  *
102
117
  * @example
103
118
  * ```typescript
104
119
  * const message = normalizeCreateStateMachine({
105
120
  * fiberId: '...',
106
- * definition: { states: { INIT: { id: { value: 'INIT' }, isFinal: false } }, ... },
121
+ * definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
107
122
  * initialData: {}
108
123
  * });
109
- * // message now has parentFiberId: null, participants: null, definition.metadata: null, etc.
124
+ * // Optional fields are absent (not null): no parentFiberId, no metadata, etc.
110
125
  * ```
111
126
  */
112
127
  function normalizeCreateStateMachine(msg) {
113
- return {
128
+ const result = {
114
129
  fiberId: msg.fiberId,
115
130
  definition: normalizeDefinition(msg.definition),
116
131
  initialData: msg.initialData ?? {},
117
- parentFiberId: msg.parentFiberId ?? null,
118
- participants: msg.participants ?? null,
119
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;
120
140
  }
121
141
  exports.normalizeCreateStateMachine = normalizeCreateStateMachine;
122
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. Specifically, ensures all `Option[A]=None` fields are
6
- * present as explicit `null` values, matching what circe's magnolia encoder
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 necessary because metakit's `JsonBinaryCodec.deriveDataUpdate`
10
- * (rc.8) canonicalizes the circe-encoded JSON **including null fields**.
11
- * If the TypeScript client omits optional fields (undefined), the canonical
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
- * Schema mapping (Scala TypeScript):
15
- * - `Option[A] = None` `null` (must be explicit, not undefined/absent)
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
- return {
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
@@ -77,43 +86,54 @@ function normalizeDefinition(def) {
77
86
  }
78
87
  const transitions = def.transitions ?? [];
79
88
  // Strip FiberAppMetadata if present — it's TypeScript-only, not part of wire format.
80
- // The Scala schema has `metadata: Option[Json] = None`, so use null for wire format.
81
- const wireMetadata = isFiberAppMetadata(def.metadata) ? null : (def.metadata ?? null);
82
- return {
89
+ // Omit metadata entirely when null/FiberAppMetadata (dropNullValues = true on Scala side).
90
+ const wireMetadata = isFiberAppMetadata(def.metadata) ? undefined : def.metadata;
91
+ const result = {
83
92
  states: normalizedStates,
84
93
  initialState: def.initialState,
85
94
  transitions: transitions.map(normalizeTransition),
86
- metadata: wireMetadata,
87
95
  };
96
+ if (wireMetadata != null) {
97
+ result.metadata = wireMetadata;
98
+ }
99
+ return result;
88
100
  }
89
101
  /**
90
102
  * Normalize a CreateStateMachine message for wire format
91
103
  *
92
- * Ensures all Option/default fields are explicit in wire format:
93
- * - definition.metadata null when absent
94
- * - definition.states[*].metadata null when absent
95
- * - definition.transitions[*].dependencies → [] when absent
96
- * - parentFiberIdnull when absent
97
- * - participantsnull when absent (Optional Set[Address] for multi-party signing)
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.metadataOMITTED when absent/FiberAppMetadata
109
+ * - definition.states[*].metadataOMITTED 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)
98
113
  *
99
114
  * @example
100
115
  * ```typescript
101
116
  * const message = normalizeCreateStateMachine({
102
117
  * fiberId: '...',
103
- * definition: { states: { INIT: { id: { value: 'INIT' }, isFinal: false } }, ... },
118
+ * definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
104
119
  * initialData: {}
105
120
  * });
106
- * // message now has parentFiberId: null, participants: null, definition.metadata: null, etc.
121
+ * // Optional fields are absent (not null): no parentFiberId, no metadata, etc.
107
122
  * ```
108
123
  */
109
124
  export function normalizeCreateStateMachine(msg) {
110
- return {
125
+ const result = {
111
126
  fiberId: msg.fiberId,
112
127
  definition: normalizeDefinition(msg.definition),
113
128
  initialData: msg.initialData ?? {},
114
- parentFiberId: msg.parentFiberId ?? null,
115
- participants: msg.participants ?? null,
116
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;
117
137
  }
118
138
  /**
119
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. Specifically, ensures all `Option[A]=None` fields are
6
- * present as explicit `null` values, matching what circe's magnolia encoder
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 necessary because metakit's `JsonBinaryCodec.deriveDataUpdate`
10
- * (rc.8) canonicalizes the circe-encoded JSON **including null fields**.
11
- * If the TypeScript client omits optional fields (undefined), the canonical
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
- * Schema mapping (Scala TypeScript):
15
- * - `Option[A] = None` `null` (must be explicit, not undefined/absent)
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
- * Ensures all Option/default fields are explicit in wire format:
24
- * - definition.metadata null when absent
25
- * - definition.states[*].metadata null when absent
26
- * - definition.transitions[*].dependencies → [] when absent
27
- * - parentFiberIdnull when absent
28
- * - participantsnull when absent (Optional Set[Address] for multi-party signing)
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.metadataOMITTED when absent/FiberAppMetadata
32
+ * - definition.states[*].metadataOMITTED 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: { value: 'INIT' }, isFinal: false } }, ... },
41
+ * definition: { states: { INIT: { id: 'INIT', isFinal: false } }, ... },
35
42
  * initialData: {}
36
43
  * });
37
- * // message now has parentFiberId: null, participants: null, definition.metadata: null, etc.
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ottochain/sdk",
3
- "version": "2.2.3",
3
+ "version": "2.2.4",
4
4
  "description": "TypeScript SDK for ottochain metagraph operations - signing, encoding, and network interactions",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",