Skip to content

Commit cc14347

Browse files
authored
Merge pull request #82 from kaleido-io/1.0-backport
Backport fixes from 1.2 to 1.0
2 parents 7449f0e + 539d538 commit cc14347

File tree

8 files changed

+526
-117
lines changed

8 files changed

+526
-117
lines changed

lib/firefly.ts

Lines changed: 231 additions & 56 deletions
Large diffs are not rendered by default.

lib/http.ts

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,45 @@ import {
55
FireFlyCreateOptions,
66
FireFlyGetOptions,
77
FireFlyError,
8+
FireFlyReplaceOptions,
9+
FireFlyUpdateOptions,
10+
FireFlyDeleteOptions,
11+
FireFlyIdempotencyError,
812
} from './interfaces';
913

1014
function isSuccess(status: number) {
1115
return status >= 200 && status < 300;
1216
}
1317

1418
export function mapConfig(
15-
options: FireFlyGetOptions | FireFlyCreateOptions | undefined,
19+
options:
20+
| FireFlyGetOptions
21+
| FireFlyUpdateOptions
22+
| FireFlyReplaceOptions
23+
| FireFlyCreateOptions
24+
| FireFlyDeleteOptions
25+
| undefined,
1626
params?: any,
1727
): AxiosRequestConfig {
18-
return {
28+
const config: AxiosRequestConfig = {
1929
...options?.requestConfig,
20-
params: {
21-
...params,
22-
confirm: options?.confirm,
23-
},
30+
params,
2431
};
32+
if (options !== undefined) {
33+
if ('confirm' in options) {
34+
config.params = {
35+
...config.params,
36+
confirm: options.confirm,
37+
};
38+
}
39+
if ('publish' in options) {
40+
config.params = {
41+
...config.params,
42+
publish: options.publish,
43+
};
44+
}
45+
}
46+
return config;
2547
}
2648

2749
export default class HttpBase {
@@ -35,17 +57,28 @@ export default class HttpBase {
3557
this.options = this.setDefaults(options);
3658
this.rootHttp = axios.create({
3759
...options.requestConfig,
38-
baseURL: `${options.host}/api/v1`,
60+
baseURL: this.options.baseURL,
3961
});
4062
this.http = axios.create({
4163
...options.requestConfig,
42-
baseURL: `${options.host}/api/v1/namespaces/${this.options.namespace}`,
64+
baseURL: this.options.namespaceBaseURL,
4365
});
4466
}
4567

4668
private setDefaults(options: FireFlyOptionsInput): FireFlyOptions {
69+
const baseURLSet = (options.baseURL ?? '') !== '' && (options.namespaceBaseURL ?? '' !== '');
70+
if (!baseURLSet && (options.host ?? '') === '') {
71+
throw new Error('Invalid options. Option host, or baseURL and namespaceBaseURL must be set.');
72+
}
73+
if ((options.host ?? '') === '' && (options.websocket?.host ?? '') === '') {
74+
throw new Error('Invalid options. Option host, or websocket.host must be set.');
75+
}
4776
return {
4877
...options,
78+
baseURL: baseURLSet ? options.baseURL : `${options.host}/api/v1`,
79+
namespaceBaseURL: baseURLSet
80+
? options.namespaceBaseURL
81+
: `${options.host}/api/v1/namespaces/${options.namespace}`,
4982
namespace: options.namespace ?? 'default',
5083
websocket: {
5184
...options.websocket,
@@ -59,8 +92,12 @@ export default class HttpBase {
5992
protected async wrapError<T>(response: Promise<AxiosResponse<T>>) {
6093
return response.catch((err) => {
6194
if (axios.isAxiosError(err)) {
62-
const errorMessage = err.response?.data?.error;
63-
const ffError = new FireFlyError(errorMessage ?? err.message);
95+
const errorMessage = err.response?.data?.error ?? err.message;
96+
const errorClass =
97+
errorMessage?.includes('FF10430') || errorMessage?.includes('FF10431')
98+
? FireFlyIdempotencyError
99+
: FireFlyError;
100+
const ffError = new errorClass(errorMessage, err, err.request.path);
64101
if (this.errorHandler !== undefined) {
65102
this.errorHandler(ffError);
66103
}
@@ -92,13 +129,18 @@ export default class HttpBase {
92129
return response.data;
93130
}
94131

95-
protected async replaceOne<T>(url: string, data: any) {
96-
const response = await this.wrapError(this.http.put<T>(url, data));
132+
protected async updateOne<T>(url: string, data: any, options?: FireFlyUpdateOptions) {
133+
const response = await this.wrapError(this.http.patch<T>(url, data, mapConfig(options)));
134+
return response.data;
135+
}
136+
137+
protected async replaceOne<T>(url: string, data: any, options?: FireFlyReplaceOptions) {
138+
const response = await this.wrapError(this.http.put<T>(url, data, mapConfig(options)));
97139
return response.data;
98140
}
99141

100-
protected async deleteOne<T>(url: string) {
101-
await this.wrapError(this.http.delete<T>(url));
142+
protected async deleteOne<T>(url: string, options?: FireFlyDeleteOptions) {
143+
await this.wrapError(this.http.delete<T>(url, mapConfig(options)));
102144
}
103145

104146
onError(handler: (err: FireFlyError) => void) {

lib/interfaces.ts

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import * as http from 'http';
12
import { AxiosRequestConfig } from 'axios';
3+
import * as WebSocket from 'ws';
24
import { operations } from './schema';
35

46
/**
@@ -13,23 +15,35 @@ import { operations } from './schema';
1315

1416
// General
1517

16-
export class FireFlyError extends Error {}
18+
export class FireFlyError extends Error {
19+
constructor(message?: string, public originalError?: Error, public path?: string) {
20+
super(message);
21+
}
22+
}
23+
24+
export class FireFlyIdempotencyError extends FireFlyError {}
1725

18-
export interface FireFlyGetOptions {
19-
confirm: undefined;
26+
interface FireFlyBaseHttpOptions {
2027
requestConfig?: AxiosRequestConfig;
2128
}
2229

23-
export interface FireFlyCreateOptions {
30+
export interface FireFlyGetOptions extends FireFlyBaseHttpOptions {}
31+
export interface FireFlyUpdateOptions extends FireFlyBaseHttpOptions {}
32+
export interface FireFlyReplaceOptions extends FireFlyBaseHttpOptions {}
33+
export interface FireFlyDeleteOptions extends FireFlyBaseHttpOptions {}
34+
35+
export interface FireFlyCreateOptions extends FireFlyBaseHttpOptions {
2436
confirm?: boolean;
25-
requestConfig?: AxiosRequestConfig;
37+
publish?: boolean;
2638
}
2739

2840
export interface FireFlyOptionsInput {
2941
host: string;
3042
namespace?: string;
3143
username?: string;
3244
password?: string;
45+
baseURL?: string;
46+
namespaceBaseURL?: string;
3347
websocket?: {
3448
host?: string;
3549
reconnectDelay?: number;
@@ -47,24 +61,50 @@ export interface FireFlyOptions extends FireFlyOptionsInput {
4761
};
4862
}
4963

64+
export interface FireFlyWebSocketSender {
65+
send: (json: JSON) => void;
66+
}
67+
68+
export interface FireFlyWebSocketConnectCallback {
69+
(sender: FireFlyWebSocketSender): void | Promise<void>;
70+
}
71+
5072
export interface FireFlyWebSocketOptions {
5173
host: string;
5274
namespace: string;
5375
subscriptions: string[];
5476
username?: string;
5577
password?: string;
5678
ephemeral?: FireFlyEphemeralSubscription;
57-
autoack: boolean;
79+
autoack?: boolean;
80+
noack?: boolean;
5881
reconnectDelay: number;
5982
heartbeatInterval: number;
83+
socketOptions?: WebSocket.ClientOptions | http.ClientRequestArgs;
84+
afterConnect?: FireFlyWebSocketConnectCallback;
6085
}
6186

87+
// Namespace
88+
export type FireFlyNamespaceResponse = Required<
89+
operations['getNamespace']['responses']['200']['content']['application/json']
90+
>;
91+
6292
// Network
6393

94+
export type FireFlyIdentityFilter = operations['getIdentities']['parameters']['query'];
6495
export type FireFlyOrganizationFilter = operations['getNetworkOrgs']['parameters']['query'];
6596
export type FireFlyNodeFilter = operations['getNetworkNodes']['parameters']['query'];
6697
export type FireFlyVerifierFilter = operations['getVerifiers']['parameters']['query'];
6798

99+
export type FireFlyIdentityRequest =
100+
operations['postNewIdentity']['requestBody']['content']['application/json'];
101+
102+
export type FireFlyIdentityResponse = Required<
103+
operations['getIdentityByID']['responses']['200']['content']['application/json']
104+
>;
105+
export type FireFlyIdentitiesResponse = Required<
106+
operations['getIdentities']['responses']['200']['content']['application/json']
107+
>;
68108
export type FireFlyOrganizationResponse = Required<
69109
operations['getNetworkOrg']['responses']['200']['content']['application/json']
70110
>;
@@ -108,20 +148,21 @@ export interface FireFlyEphemeralSubscription extends FireFlySubscriptionBase {
108148
}
109149

110150
export interface FireFlyEnrichedEvent extends FireFlyEventResponse {
111-
blockchainEvent?: unknown;
112-
contractAPI?: unknown;
113-
contractInterface?: unknown;
151+
blockchainEvent?: FireFlyBlockchainEventResponse;
152+
contractAPI?: FireFlyContractAPIResponse;
153+
contractInterface?: FireFlyContractInterfaceResponse;
114154
datatype?: FireFlyDatatypeResponse;
115-
identity?: unknown;
155+
identity?: FireFlyIdentityResponse;
116156
message?: FireFlyMessageResponse;
117-
namespaceDetails?: unknown;
118-
tokenApproval?: unknown;
157+
tokenApproval?: FireFlyTokenApprovalResponse;
119158
tokenPool?: FireFlyTokenPoolResponse;
120159
tokenTransfer?: FireFlyTokenTransferResponse;
121160
transaction?: FireFlyTransactionResponse;
161+
operation?: FireFlyOperationResponse;
122162
}
123163

124-
export interface FireFlyEventDelivery extends FireFlyEnrichedEvent {
164+
export interface FireFlyEventDelivery extends Omit<FireFlyEnrichedEvent, 'type'> {
165+
type: FireFlyEnrichedEvent['type'] | 'protocol_error';
125166
subscription: {
126167
id: string;
127168
name: string;
@@ -145,11 +186,17 @@ export type FireFlyDataFilter = operations['getData']['parameters']['query'];
145186

146187
export type FireFlyDataRequest =
147188
operations['postData']['requestBody']['content']['application/json'];
189+
export type FireFlyDataBlobRequest =
190+
operations['postData']['requestBody']['content']['multipart/form-data'];
148191

149192
export type FireFlyDataResponse = Required<
150193
operations['getDataByID']['responses']['200']['content']['application/json']
151194
>;
152195

196+
export const FireFlyDataBlobRequestDefaults: FireFlyDataBlobRequest = {
197+
autometa: 'true',
198+
};
199+
153200
// Messages
154201

155202
export type FireFlyMessageFilter = operations['getMsgs']['parameters']['query'];
@@ -166,6 +213,9 @@ export type FireFlyMessageResponse = Required<
166213
export type FireFlyBatchResponse = Required<
167214
operations['getBatchByID']['responses']['200']['content']['application/json']
168215
>;
216+
export type FireFlyGroupResponse = Required<
217+
operations['getGroupByHash']['responses']['200']['content']['application/json']
218+
>;
169219

170220
export interface FireFlyPrivateSendOptions extends FireFlyCreateOptions {
171221
requestReply?: boolean;
@@ -184,6 +234,8 @@ export type FireFlyTokenPoolResponse = Required<
184234

185235
// Token Transfers
186236

237+
export type FireFlyTokenTransferFilter = operations['getTokenTransfers']['parameters']['query'];
238+
187239
export type FireFlyTokenMintRequest =
188240
operations['postTokenMint']['requestBody']['content']['application/json'];
189241
export type FireFlyTokenBurnRequest =
@@ -199,9 +251,23 @@ export type FireFlyTokenTransferResponse = Required<
199251

200252
export type FireFlyTokenBalanceFilter = operations['getTokenBalances']['parameters']['query'];
201253

202-
export type FireFlyTokenBalanceResponse = Required<
254+
type BalancesList = Required<
203255
operations['getTokenBalances']['responses']['200']['content']['application/json']
204256
>;
257+
const balances: BalancesList = [];
258+
export type FireFlyTokenBalanceResponse = typeof balances[0];
259+
260+
// Token Approvals
261+
262+
export type FireFlyTokenApprovalFilter = operations['getTokenApprovals']['parameters']['query'];
263+
264+
export type FireFlyTokenApprovalRequest =
265+
operations['postTokenApproval']['requestBody']['content']['application/json'];
266+
type ApprovalsList =
267+
operations['getTokenApprovals']['responses']['200']['content']['application/json'];
268+
269+
const approvals: ApprovalsList = [];
270+
export type FireFlyTokenApprovalResponse = typeof approvals[0];
205271

206272
// Operations + Transactions
207273

@@ -241,3 +307,27 @@ export type FireFlyContractAPIResponse = Required<
241307
export type FireFlyContractListenerResponse = Required<
242308
operations['getContractListenerByNameOrID']['responses']['200']['content']['application/json']
243309
>;
310+
311+
export type FireFlyContractInvokeRequest =
312+
operations['postContractInvoke']['requestBody']['content']['application/json'];
313+
export type FireFlyContractAPIInvokeRequest =
314+
operations['postContractAPIInvoke']['requestBody']['content']['application/json'];
315+
export type FireFlyContractInvokeResponse = Required<
316+
operations['postContractInvoke']['responses']['202']['content']['application/json']
317+
>;
318+
319+
export type FireFlyContractQueryRequest =
320+
operations['postContractQuery']['requestBody']['content']['application/json'];
321+
export type FireFlyContractAPIQueryRequest =
322+
operations['postContractAPIQuery']['requestBody']['content']['application/json'];
323+
export type FireFlyContractQueryResponse = Required<
324+
operations['postContractQuery']['responses']['200']['content']['application/json']
325+
>;
326+
327+
// Blockchain Events
328+
329+
export type FireFlyBlockchainEventFilter = operations['getBlockchainEvents']['parameters']['query'];
330+
331+
export type FireFlyBlockchainEventResponse = Required<
332+
operations['getBlockchainEventByID']['responses']['200']['content']['application/json']
333+
>;

0 commit comments

Comments
 (0)