@wishknish/knishio-client-js 0.4.45 → 0.4.48
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/dist/client.umd.js +19 -19
- package/package.json +1 -1
- package/src/Atom.js +16 -0
- package/src/KnishIOClient.js +103 -10
- package/src/Molecule.js +68 -2
- package/src/TokenUnit.js +17 -10
- package/src/Wallet.js +7 -12
- package/src/httpClient/ApolloClient.js +19 -9
- package/src/instance/Rules/Callback.js +1 -1
- package/src/instance/Rules/Rule.js +1 -1
- package/src/libraries/ApolloLink/Client.js +18 -11
- package/src/libraries/ApolloLink/PusherLink.js +159 -151
- package/src/libraries/check.js +1 -1
- package/src/test/Test.js +96 -10
|
@@ -45,182 +45,190 @@ Please visit https://github.com/WishKnish/KnishIO-Client-JS for information.
|
|
|
45
45
|
|
|
46
46
|
License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
|
|
47
47
|
*/
|
|
48
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
ApolloLink,
|
|
50
|
+
Observable
|
|
51
|
+
} from '@apollo/client/core';
|
|
49
52
|
import Pusher from 'pusher-js';
|
|
50
53
|
import { parse } from 'uri-js';
|
|
51
54
|
import CodeException from '../../exception/CodeException';
|
|
55
|
+
import Dot from '../Dot';
|
|
52
56
|
|
|
53
57
|
|
|
54
58
|
class PusherLink extends ApolloLink {
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
// constructor( options ) {
|
|
61
|
+
constructor ( {
|
|
62
|
+
socketUri,
|
|
63
|
+
authEndpoint,
|
|
64
|
+
appKey = 'knishio'
|
|
65
|
+
} ) {
|
|
66
|
+
console.log( 'PusherLink::constructor()...' );
|
|
67
|
+
super();
|
|
60
68
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
this.socketUri = socketUri;
|
|
70
|
+
this.authEndpoint = authEndpoint;
|
|
71
|
+
this.appKey = appKey;
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
* @param {string} socketUri
|
|
72
|
-
*/
|
|
73
|
-
setTransport ( socketUri ) {
|
|
74
|
-
|
|
75
|
-
console.log( `Connecting to socket endpoint ${ socketUri }...` );
|
|
76
|
-
|
|
77
|
-
const wsPath = parse( socketUri );
|
|
78
|
-
|
|
79
|
-
if ( ![ 'ws', 'wss' ].includes( wsPath.scheme ) ) {
|
|
80
|
-
throw new CodeException( 'Incorrect scheme for the socket' );
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
this.transport = new Pusher( this.appKey, {
|
|
84
|
-
auth: {
|
|
85
|
-
headers: {
|
|
86
|
-
'X-Auth-Token': this.getAuthToken(),
|
|
87
|
-
Accept: 'application/json'
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
wsHost: wsPath.host,
|
|
91
|
-
wsPort: wsPath.port,
|
|
92
|
-
forceTLS: wsPath.scheme === 'wss',
|
|
93
|
-
encrypted: true,
|
|
94
|
-
enabledTransports: [ wsPath.scheme ],
|
|
95
|
-
authEndpoint: this.authEndpoint
|
|
96
|
-
} );
|
|
97
|
-
}
|
|
73
|
+
this.setAuthToken( '' );
|
|
74
|
+
this.setTransport( this.getSocketUri() );
|
|
75
|
+
}
|
|
98
76
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
*
|
|
105
|
-
* @param {string} name
|
|
106
|
-
* @returns {Channel|null}
|
|
107
|
-
*/
|
|
108
|
-
channel( name ) {
|
|
109
|
-
return this.transport.channel( name ) || null;
|
|
110
|
-
}
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @param {string} socketUri
|
|
80
|
+
*/
|
|
81
|
+
setTransport ( socketUri ) {
|
|
111
82
|
|
|
112
|
-
|
|
113
|
-
*
|
|
114
|
-
* @return {string}
|
|
115
|
-
*/
|
|
116
|
-
getAuthToken () {
|
|
117
|
-
return this.auth;
|
|
118
|
-
}
|
|
83
|
+
console.log( `Connecting to socket endpoint ${ socketUri }...` );
|
|
119
84
|
|
|
120
|
-
|
|
121
|
-
* @param {string} auth
|
|
122
|
-
*/
|
|
123
|
-
setAuthToken ( auth ) {
|
|
124
|
-
this.auth = auth;
|
|
125
|
-
}
|
|
85
|
+
const wsPath = parse( socketUri );
|
|
126
86
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
*/
|
|
130
|
-
getSocketUri () {
|
|
131
|
-
return this.socketUri;
|
|
87
|
+
if ( ![ 'ws', 'wss' ].includes( wsPath.scheme ) ) {
|
|
88
|
+
throw new CodeException( 'Incorrect scheme for the socket' );
|
|
132
89
|
}
|
|
133
90
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
91
|
+
this.transport = new Pusher( this.appKey, {
|
|
92
|
+
auth: {
|
|
93
|
+
headers: {
|
|
94
|
+
'X-Auth-Token': this.getAuthToken(),
|
|
95
|
+
Accept: 'application/json'
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
wsHost: wsPath.host,
|
|
99
|
+
wsPort: wsPath.port,
|
|
100
|
+
forceTLS: wsPath.scheme === 'wss',
|
|
101
|
+
encrypted: true,
|
|
102
|
+
enabledTransports: [ wsPath.scheme ],
|
|
103
|
+
authEndpoint: this.authEndpoint
|
|
104
|
+
} );
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
disconnect () {
|
|
108
|
+
this.transport.disconnect();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
*
|
|
113
|
+
* @param {string} name
|
|
114
|
+
* @returns {Channel|null}
|
|
115
|
+
*/
|
|
116
|
+
channel ( name ) {
|
|
117
|
+
return this.transport.channel( name ) || null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
*
|
|
122
|
+
* @return {string}
|
|
123
|
+
*/
|
|
124
|
+
getAuthToken () {
|
|
125
|
+
return this.auth;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {string} auth
|
|
130
|
+
*/
|
|
131
|
+
setAuthToken ( auth ) {
|
|
132
|
+
this.auth = auth;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @return {string|null}
|
|
137
|
+
*/
|
|
138
|
+
getSocketUri () {
|
|
139
|
+
return this.socketUri;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
request ( operation, forward ) {
|
|
143
|
+
this.transport.config.auth.headers[ 'X-Auth-Token' ] = this.getAuthToken();
|
|
144
|
+
|
|
145
|
+
const subscribeObservable = new Observable( ( _observer ) => {
|
|
146
|
+
//
|
|
147
|
+
} );
|
|
148
|
+
|
|
149
|
+
// Capture the super method
|
|
150
|
+
const prevSubscribe = subscribeObservable.subscribe.bind( subscribeObservable );
|
|
151
|
+
|
|
152
|
+
// Override subscribe to return an `unsubscribe` object, see
|
|
153
|
+
// https://github.com/apollographql/subscriptions-transport-ws/blob/master/src/client.ts#L182-L212
|
|
154
|
+
subscribeObservable.subscribe = ( observerOrNext, onError, onComplete ) => {
|
|
155
|
+
prevSubscribe( observerOrNext, onError, onComplete );
|
|
156
|
+
|
|
157
|
+
const observer = getObserver( observerOrNext, onError, onComplete );
|
|
158
|
+
|
|
159
|
+
let subscriptionChannel;
|
|
160
|
+
|
|
161
|
+
forward( operation ).subscribe( {
|
|
162
|
+
next: ( data ) => {
|
|
163
|
+
// If the operation has the subscription channel, it's a subscription
|
|
164
|
+
subscriptionChannel = Dot.get( data, 'extensions.lighthouse_subscriptions.channel' );
|
|
165
|
+
|
|
166
|
+
// No subscription found in the response, pipe data through
|
|
167
|
+
if ( !subscriptionChannel ) {
|
|
168
|
+
observer.next( data );
|
|
169
|
+
observer.complete();
|
|
170
|
+
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.subscribeToChannel( subscriptionChannel, observer );
|
|
175
|
+
}
|
|
176
|
+
} );
|
|
177
|
+
|
|
178
|
+
// Return an object that will unsubscribe_if the query was a subscription
|
|
179
|
+
return {
|
|
180
|
+
closed: false,
|
|
181
|
+
unsubscribe: () => {
|
|
182
|
+
subscriptionChannel &&
|
|
183
|
+
this.unsubscribeFromChannel( subscriptionChannel );
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
};
|
|
179
187
|
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
return subscribeObservable;
|
|
189
|
+
}
|
|
182
190
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
subscribeToChannel ( subscriptionChannel, observer ) {
|
|
192
|
+
this.transport
|
|
193
|
+
.subscribe( subscriptionChannel )
|
|
194
|
+
.bind( 'lighthouse-subscription', ( payload ) => {
|
|
195
|
+
if ( !payload.more ) {
|
|
196
|
+
this.unsubscribeFromChannel( subscriptionChannel );
|
|
189
197
|
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
observer.complete();
|
|
199
|
+
}
|
|
192
200
|
|
|
193
|
-
|
|
201
|
+
const result = payload.result;
|
|
194
202
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
if ( result ) {
|
|
204
|
+
observer.next( result );
|
|
205
|
+
}
|
|
206
|
+
} );
|
|
207
|
+
}
|
|
200
208
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
209
|
+
unsubscribeFromChannel ( subscriptionChannel ) {
|
|
210
|
+
this.transport.unsubscribe( subscriptionChannel );
|
|
211
|
+
}
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
// Turn `subscribe` arguments into an observer-like thing, see getObserver
|
|
207
215
|
// https://github.com/apollographql/subscriptions-transport-ws/blob/master/src/client.ts#L329-L343
|
|
208
|
-
function getObserver( observerOrNext, onError, onComplete ) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
216
|
+
function getObserver ( observerOrNext, onError, onComplete ) {
|
|
217
|
+
if ( typeof observerOrNext === 'function' ) {
|
|
218
|
+
// Duck-type an observer
|
|
219
|
+
return {
|
|
220
|
+
next: ( v ) => observerOrNext( v ),
|
|
221
|
+
error: ( e ) => onError && onError( e ),
|
|
222
|
+
complete: () => onComplete && onComplete()
|
|
223
|
+
};
|
|
224
|
+
} else {
|
|
225
|
+
// Make an object that calls to the given object, with safety checks
|
|
226
|
+
return {
|
|
227
|
+
next: ( v ) => observerOrNext.next && observerOrNext.next( v ),
|
|
228
|
+
error: ( e ) => observerOrNext.error && observerOrNext.error( e ),
|
|
229
|
+
complete: () => observerOrNext.complete && observerOrNext.complete()
|
|
230
|
+
};
|
|
231
|
+
}
|
|
224
232
|
}
|
|
225
233
|
|
|
226
234
|
export default PusherLink;
|
package/src/libraries/check.js
CHANGED
|
@@ -264,7 +264,7 @@ export default class CheckMolecule {
|
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
for ( const rule of rules ) {
|
|
267
|
-
const keys = Object.keys(rule).filter( value => [ 'key', 'value', 'callback' ].includes( value ) );
|
|
267
|
+
const keys = Object.keys( rule ).filter( value => [ 'key', 'value', 'callback' ].includes( value ) );
|
|
268
268
|
|
|
269
269
|
if ( keys.length < 3 ) {
|
|
270
270
|
throw new MetaMissingException( 'Check::isotopeR() - Necessary rule fields are missing!' );
|
package/src/test/Test.js
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
generateSecret
|
|
6
6
|
} from '../libraries/crypto';
|
|
7
7
|
import ResponseMolecule from '../response/ResponseProposeMolecule';
|
|
8
|
+
import TokenUnit from '../TokenUnit';
|
|
8
9
|
|
|
9
10
|
/*
|
|
10
11
|
|
|
@@ -21,7 +22,7 @@ export default class Test {
|
|
|
21
22
|
/**
|
|
22
23
|
* Run all
|
|
23
24
|
*/
|
|
24
|
-
static async run( uris ) {
|
|
25
|
+
static async run ( uris ) {
|
|
25
26
|
for ( let i in uris ) {
|
|
26
27
|
let test = new Test( uris[ i ] );
|
|
27
28
|
await test.testAll();
|
|
@@ -36,7 +37,7 @@ export default class Test {
|
|
|
36
37
|
constructor ( graphqlUrl, encrypt = false ) {
|
|
37
38
|
this.encrypt = encrypt;
|
|
38
39
|
this.secrets = [ generateSecret(), generateSecret() ];
|
|
39
|
-
this.tokenSlugs = [ 'TESTTOKEN', 'UTENVSTACKABLE', 'UTSTACKUNIT', 'UTENVSTACKUNIT' ];
|
|
40
|
+
this.tokenSlugs = [ 'TESTTOKEN', 'UTENVSTACKABLE', 'UTSTACKUNIT', 'UTENVSTACKUNIT', 'UTSTACKUNITZONES' ];
|
|
40
41
|
this.graphqlUrl = graphqlUrl;
|
|
41
42
|
console.log( `---------- GraphQL URI: ${ this.graphqlUrl }` );
|
|
42
43
|
|
|
@@ -60,6 +61,26 @@ export default class Test {
|
|
|
60
61
|
[ 'unit_id_14', 'unit_id_14' ],
|
|
61
62
|
[ 'unit_id_15', 'unit_id_15' ]
|
|
62
63
|
];
|
|
64
|
+
|
|
65
|
+
// Generate token units with fragment zones
|
|
66
|
+
let getTokenUnitsFZ = ( tokenUnits, from = 0 ) => {
|
|
67
|
+
let result = [];
|
|
68
|
+
tokenUnits.forEach( ( tokenUnit, key ) => {
|
|
69
|
+
let tokenUnitFZ = Array.from( tokenUnit );
|
|
70
|
+
tokenUnitFZ.push( { fragmentZone: from + key } );
|
|
71
|
+
result.push( tokenUnitFZ );
|
|
72
|
+
} );
|
|
73
|
+
return result;
|
|
74
|
+
};
|
|
75
|
+
this.tokenUnitsFZ = getTokenUnitsFZ( this.tokenUnits );
|
|
76
|
+
this.replenishTokenUnitsFZ = getTokenUnitsFZ( Array.from( this.replenishTokenUnits ), this.tokenUnits.length );
|
|
77
|
+
this.fragmentZones = this.tokenUnitsFZ.length + this.replenishTokenUnitsFZ.length;
|
|
78
|
+
|
|
79
|
+
// Init fused token unit IDs
|
|
80
|
+
this.fusedTokenUnitIds = [];
|
|
81
|
+
this.tokenUnitsFZ.slice( 0, 5 ).forEach( ( tokenUnitData ) => {
|
|
82
|
+
this.fusedTokenUnitIds.push( tokenUnitData[ 0 ] );
|
|
83
|
+
} );
|
|
63
84
|
}
|
|
64
85
|
|
|
65
86
|
|
|
@@ -67,17 +88,14 @@ export default class Test {
|
|
|
67
88
|
* Test all KnishIOClient functions
|
|
68
89
|
*/
|
|
69
90
|
async testAll () {
|
|
70
|
-
console.info(`Executing test for: ${ this.graphqlUrl }...`);
|
|
71
|
-
|
|
72
|
-
/*
|
|
73
|
-
await this.testTokenExpiration();
|
|
74
|
-
return;
|
|
75
|
-
*/
|
|
91
|
+
console.info( `Executing test for: ${ this.graphqlUrl }...` );
|
|
76
92
|
|
|
77
93
|
await this.client( this.secrets[ 0 ] );
|
|
78
94
|
await this.client( this.secrets[ 1 ] );
|
|
79
95
|
|
|
80
96
|
await this.testCreateToken();
|
|
97
|
+
await this.testFuseToken();
|
|
98
|
+
return;
|
|
81
99
|
await this.testCreateWallet();
|
|
82
100
|
await this.testCreateMeta();
|
|
83
101
|
await this.testCreateIdentifier();
|
|
@@ -185,6 +203,21 @@ export default class Test {
|
|
|
185
203
|
batchId: 'server_unit_batch_0'
|
|
186
204
|
} );
|
|
187
205
|
this.checkResponse( responses[ 3 ], 'testCreateToken.3' );
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
// Create stackable unit token
|
|
209
|
+
responses[ 4 ] = await client.createToken( {
|
|
210
|
+
token: this.tokenSlugs[ 4 ],
|
|
211
|
+
units: this.tokenUnitsFZ,
|
|
212
|
+
meta: {
|
|
213
|
+
name: this.tokenSlugs[ 4 ],
|
|
214
|
+
supply: 'replenishable',
|
|
215
|
+
fungibility: 'stackable',
|
|
216
|
+
fragmentZones: this.fragmentZones
|
|
217
|
+
},
|
|
218
|
+
batchId: 'unit_fz_batch_0'
|
|
219
|
+
} );
|
|
220
|
+
this.checkResponse( responses[ 4 ], 'testCreateToken.4' );
|
|
188
221
|
}
|
|
189
222
|
|
|
190
223
|
/**
|
|
@@ -226,9 +259,9 @@ export default class Test {
|
|
|
226
259
|
code: '1234'
|
|
227
260
|
} );
|
|
228
261
|
|
|
229
|
-
console.log(
|
|
262
|
+
console.log( ' ############### testCreateIdentifier ###############' );
|
|
230
263
|
if ( response.reason() !== 'Outdated code' ) {
|
|
231
|
-
console.error( 'Error with response.' )
|
|
264
|
+
console.error( 'Error with response.' );
|
|
232
265
|
}
|
|
233
266
|
this.debug( response );
|
|
234
267
|
}
|
|
@@ -327,6 +360,59 @@ export default class Test {
|
|
|
327
360
|
this.checkResponse( response, 'testReplenishUnitToken' );
|
|
328
361
|
}
|
|
329
362
|
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
*
|
|
366
|
+
* @returns {Promise<void>}
|
|
367
|
+
*/
|
|
368
|
+
async testFuseToken () {
|
|
369
|
+
|
|
370
|
+
let tokenSlug = this.tokenSlugs[ 4 ];
|
|
371
|
+
|
|
372
|
+
let recipientSecret = generateSecret();
|
|
373
|
+
let recipientClient = await this.client( recipientSecret );
|
|
374
|
+
|
|
375
|
+
let fusedTokenUnit = new TokenUnit( 'fusedTokenUnitId' );
|
|
376
|
+
|
|
377
|
+
let client = await this.client( this.secrets[ 0 ] );
|
|
378
|
+
let response = await client.fuseToken( {
|
|
379
|
+
recipient: recipientSecret,
|
|
380
|
+
tokenSlug: tokenSlug,
|
|
381
|
+
newTokenUnit: fusedTokenUnit,
|
|
382
|
+
fusedTokenUnitIds: this.fusedTokenUnitIds
|
|
383
|
+
} );
|
|
384
|
+
this.checkResponse( response, 'testReplenishToken' );
|
|
385
|
+
|
|
386
|
+
let walletRecipient = ( await recipientClient.queryBalance( { token: tokenSlug } ) ).payload();
|
|
387
|
+
let walletRemainder = ( await client.queryBalance( { token: tokenSlug } ) ).payload();
|
|
388
|
+
|
|
389
|
+
// Check recipient wallet
|
|
390
|
+
console.assert( walletRecipient.tokenUnits.length, 1 );
|
|
391
|
+
console.assert( walletRecipient.tokenUnits[ 0 ].id, 'fusedTokenUnitId' );
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
// --- Check fused token units in the recipient wallet
|
|
395
|
+
let fusedTokenUnits = walletRecipient.tokenUnits[ 0 ].getFusedTokenUnits();
|
|
396
|
+
console.assert( fusedTokenUnits.length, this.fusedTokenUnitIds.length );
|
|
397
|
+
// Get token unit IDs from the fused meta data of the fused token unit
|
|
398
|
+
let dbFusedTokenUnitIds = [];
|
|
399
|
+
fusedTokenUnits.forEach( ( tokenUnit ) => {
|
|
400
|
+
dbFusedTokenUnitIds.push( tokenUnit[ 0 ] );
|
|
401
|
+
} );
|
|
402
|
+
// ---
|
|
403
|
+
|
|
404
|
+
// --- Check remainder token units
|
|
405
|
+
console.assert( walletRemainder.tokenUnits.length, 6 );
|
|
406
|
+
let remainderTokenUnitIds = [];
|
|
407
|
+
walletRemainder.tokenUnits.forEach( ( tokenUnit ) => {
|
|
408
|
+
remainderTokenUnitIds.push( tokenUnit.id );
|
|
409
|
+
} );
|
|
410
|
+
console.assert(
|
|
411
|
+
remainderTokenUnitIds,
|
|
412
|
+
[ 'unit_id_6', 'unit_id_7', 'unit_id_8', 'unit_id_9', 'unit_id_10', 'unit_id_11' ]
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
330
416
|
/**
|
|
331
417
|
*
|
|
332
418
|
*/
|