@fraym/streams 0.1.1 → 0.1.3
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/README.md +44 -8
- package/dist/client/allEvents.d.ts +3 -0
- package/dist/client/allEvents.js +25 -0
- package/dist/client/client.d.ts +14 -0
- package/dist/client/client.js +59 -0
- package/dist/client/config.d.ts +8 -0
- package/dist/client/config.js +14 -0
- package/dist/client/errors/alreadySubscribed.d.ts +3 -0
- package/dist/client/errors/alreadySubscribed.js +9 -0
- package/dist/client/event.d.ts +25 -0
- package/dist/client/event.js +38 -0
- package/dist/client/handler.d.ts +8 -0
- package/dist/client/handler.js +69 -0
- package/dist/client/init.d.ts +5 -0
- package/dist/client/init.js +34 -0
- package/dist/client/invalidateGdpr.d.ts +3 -0
- package/dist/client/invalidateGdpr.js +49 -0
- package/dist/client/publish.d.ts +4 -0
- package/dist/client/publish.js +81 -0
- package/dist/client/snapshot.d.ts +3 -0
- package/dist/client/snapshot.js +40 -0
- package/dist/client/stream.d.ts +3 -0
- package/dist/client/stream.js +21 -0
- package/dist/client/subscribe.d.ts +3 -0
- package/dist/client/subscribe.js +40 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +17 -0
- package/package.json +7 -11
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# streams-
|
|
1
|
+
# streams-nodejs
|
|
2
2
|
|
|
3
3
|
Client implementation in javascript for the event streaming service [streams](https://github.com/fraym-work/streams).
|
|
4
4
|
|
|
@@ -22,9 +22,10 @@ const client = await newClient({
|
|
|
22
22
|
### Publish events
|
|
23
23
|
|
|
24
24
|
Events are published in a transactional manner:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
|
|
26
|
+
- you can publish a set of events in a transaction
|
|
27
|
+
- if one event in your set cannot be published no event will be published
|
|
28
|
+
- as soon as all events are published they appear in their streams
|
|
28
29
|
|
|
29
30
|
You can only publish events of one topic per transaction.
|
|
30
31
|
Most of the fields of an event are optional. You do not have to use or specify them, but you can use them if you want to.
|
|
@@ -39,7 +40,7 @@ await client.publish("topic", [
|
|
|
39
40
|
},
|
|
40
41
|
// set `broadcast` to true if you want all subscribers of a group to process the event.
|
|
41
42
|
// set to false (or remove) if you want this event to be handled only once by a group of subscribers.
|
|
42
|
-
broadcast: false,
|
|
43
|
+
broadcast: false,
|
|
43
44
|
type: "event-type",
|
|
44
45
|
stream: "stream-name",
|
|
45
46
|
correlationId: uuid(),
|
|
@@ -95,11 +96,11 @@ One client instance is only able to subscribe once. If you try to subscribe twic
|
|
|
95
96
|
|
|
96
97
|
### Get all events for a given topic filter
|
|
97
98
|
|
|
98
|
-
The `getAllEvents` function uses the same filter
|
|
99
|
+
The `getAllEvents` function uses the same topic filter parameters as described for the [subscribe](#subscribe-to-events) function
|
|
99
100
|
|
|
100
101
|
```typescript
|
|
101
102
|
await client.getAllEvents(async (event: SubscriptionEvent) => {
|
|
102
|
-
// @todo: handle the event in this callback
|
|
103
|
+
// @todo: handle the event in this callback
|
|
103
104
|
});
|
|
104
105
|
```
|
|
105
106
|
|
|
@@ -108,7 +109,7 @@ await client.getAllEvents(async (event: SubscriptionEvent) => {
|
|
|
108
109
|
You will not need to use this if you use our GDPR service.
|
|
109
110
|
|
|
110
111
|
```typescript
|
|
111
|
-
await client.invalidateGdprData("tenantId", "topic-1", "grprId")
|
|
112
|
+
await client.invalidateGdprData("tenantId", "topic-1", "grprId");
|
|
112
113
|
```
|
|
113
114
|
|
|
114
115
|
### Create a snapshot of a topic
|
|
@@ -134,3 +135,38 @@ You won't lose any data if you don't. Use it for your peace of mind.
|
|
|
134
135
|
```typescript
|
|
135
136
|
client.close();
|
|
136
137
|
```
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
You'll need the following apps for a smooth development experience:
|
|
142
|
+
|
|
143
|
+
- minikube
|
|
144
|
+
- lens
|
|
145
|
+
- okteto
|
|
146
|
+
- helm
|
|
147
|
+
|
|
148
|
+
### Running the dev environment
|
|
149
|
+
|
|
150
|
+
- Start minikube if not already done:
|
|
151
|
+
|
|
152
|
+
```shell
|
|
153
|
+
minikube start
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
- add mongodb and minio to your lokal kubernetes
|
|
157
|
+
- use Makefiles in `./.dev/*`
|
|
158
|
+
- copy `.env.build` to `.env.build.local`
|
|
159
|
+
- add your personal access token (needs read access for private fraym org repositories)
|
|
160
|
+
- deploy the app to your cluster
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
make init
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- start okteto
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
make dev
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- connect your IDE to that okteto instance
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAllEvents = void 0;
|
|
4
|
+
const event_1 = require("./event");
|
|
5
|
+
const getAllEvents = async (includedTopics, excludedTopics, handler, serviceClient) => {
|
|
6
|
+
const stream = serviceClient.getEventsFromStart({
|
|
7
|
+
excludedTopics,
|
|
8
|
+
includedTopics,
|
|
9
|
+
});
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
stream.on("data", (data) => {
|
|
12
|
+
const event = (0, event_1.getSubscriptionEvent)(data);
|
|
13
|
+
if (event) {
|
|
14
|
+
handler(event);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
stream.on("end", () => {
|
|
18
|
+
resolve();
|
|
19
|
+
});
|
|
20
|
+
stream.on("error", e => {
|
|
21
|
+
reject(e);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
exports.getAllEvents = getAllEvents;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ClientConfig } from "./config";
|
|
2
|
+
import { HandlerFunc, PublishEvent, SubscriptionEvent } from "./event";
|
|
3
|
+
export interface Client {
|
|
4
|
+
getAllEvents: (handler: HandlerFunc, includedTopics?: string[], excludedTopics?: string[]) => Promise<void>;
|
|
5
|
+
getStream: (tenantId: string, stream: string) => Promise<SubscriptionEvent[]>;
|
|
6
|
+
useEventHandler: (type: string, handler: HandlerFunc) => void;
|
|
7
|
+
useEventHandlerForAllEventTypes: (handler: HandlerFunc) => void;
|
|
8
|
+
subscribe: (includedTopics?: string[], excludedTopics?: string[]) => Promise<void>;
|
|
9
|
+
publish: (topic: string, events: PublishEvent[]) => Promise<void>;
|
|
10
|
+
invalidateGdprData: (tenantId: string, topic: string, gdprId: string) => Promise<void>;
|
|
11
|
+
createSnapshot: (topic: string, toTime: Date) => Promise<void>;
|
|
12
|
+
close: () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const newClient: (config: ClientConfig) => Promise<Client>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.newClient = void 0;
|
|
4
|
+
const streams_proto_1 = require("@fraym/streams-proto");
|
|
5
|
+
const grpc_js_1 = require("@grpc/grpc-js");
|
|
6
|
+
const allEvents_1 = require("./allEvents");
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
const alreadySubscribed_1 = require("./errors/alreadySubscribed");
|
|
9
|
+
const handler_1 = require("./handler");
|
|
10
|
+
const init_1 = require("./init");
|
|
11
|
+
const invalidateGdpr_1 = require("./invalidateGdpr");
|
|
12
|
+
const publish_1 = require("./publish");
|
|
13
|
+
const snapshot_1 = require("./snapshot");
|
|
14
|
+
const stream_1 = require("./stream");
|
|
15
|
+
const subscribe_1 = require("./subscribe");
|
|
16
|
+
const newClient = async (config) => {
|
|
17
|
+
config = (0, config_1.useConfigDefaults)(config);
|
|
18
|
+
const serviceClient = new streams_proto_1.ServiceClient(config.serverAddress, grpc_js_1.credentials.createInsecure(), {
|
|
19
|
+
"grpc.keepalive_time_ms": config.keepaliveInterval,
|
|
20
|
+
"grpc.keepalive_timeout_ms": config.keepaliveTimeout,
|
|
21
|
+
"grpc.keepalive_permit_without_calls": 1,
|
|
22
|
+
});
|
|
23
|
+
const stream = await (0, init_1.initStream)(config, serviceClient);
|
|
24
|
+
const eventHandler = (0, handler_1.initEventHandler)(stream);
|
|
25
|
+
let hasSubscribed = false;
|
|
26
|
+
return {
|
|
27
|
+
getAllEvents: async (handler, includedTopics = [], excludedTopics = []) => {
|
|
28
|
+
await (0, allEvents_1.getAllEvents)(includedTopics, excludedTopics, handler, serviceClient);
|
|
29
|
+
},
|
|
30
|
+
getStream: async (tenantId, stream) => {
|
|
31
|
+
return await (0, stream_1.getStream)(tenantId, stream, serviceClient);
|
|
32
|
+
},
|
|
33
|
+
useEventHandler: (type, handler) => {
|
|
34
|
+
eventHandler.addHandler(type, handler);
|
|
35
|
+
},
|
|
36
|
+
useEventHandlerForAllEventTypes: handler => {
|
|
37
|
+
eventHandler.addHandlerForAllTypes(handler);
|
|
38
|
+
},
|
|
39
|
+
subscribe: async (includedTopics = [], excludedTopics = []) => {
|
|
40
|
+
if (hasSubscribed) {
|
|
41
|
+
throw new alreadySubscribed_1.AlreadySubscribedError();
|
|
42
|
+
}
|
|
43
|
+
return await (0, subscribe_1.sendSubscribe)(includedTopics, excludedTopics, config, stream);
|
|
44
|
+
},
|
|
45
|
+
publish: async (topic, events) => {
|
|
46
|
+
return (0, publish_1.sendPublish)(topic, events, config, stream);
|
|
47
|
+
},
|
|
48
|
+
invalidateGdprData: async (tenantId, topic, gdprId) => {
|
|
49
|
+
return await (0, invalidateGdpr_1.sendInvalidateGdpr)(tenantId, topic, gdprId, config, stream);
|
|
50
|
+
},
|
|
51
|
+
createSnapshot: async (topic, toTime) => {
|
|
52
|
+
return await (0, snapshot_1.sendSnapshot)(topic, toTime, config, stream);
|
|
53
|
+
},
|
|
54
|
+
close: () => {
|
|
55
|
+
stream.end();
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
exports.newClient = newClient;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useConfigDefaults = void 0;
|
|
4
|
+
const useConfigDefaults = (config) => {
|
|
5
|
+
var _a, _b, _c;
|
|
6
|
+
return {
|
|
7
|
+
serverAddress: config.serverAddress,
|
|
8
|
+
groupId: config.groupId,
|
|
9
|
+
ackTimeout: (_a = config.ackTimeout) !== null && _a !== void 0 ? _a : 1000,
|
|
10
|
+
keepaliveTimeout: (_b = config.keepaliveTimeout) !== null && _b !== void 0 ? _b : 3 * 1000,
|
|
11
|
+
keepaliveInterval: (_c = config.keepaliveInterval) !== null && _c !== void 0 ? _c : 40 * 1000,
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
exports.useConfigDefaults = useConfigDefaults;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AlreadySubscribedError = void 0;
|
|
4
|
+
class AlreadySubscribedError extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("streams client is already subscribed to a set of topics");
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
exports.AlreadySubscribedError = AlreadySubscribedError;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PublishEventEnvelope } from "@fraym/streams-proto";
|
|
2
|
+
export interface SubscriptionEvent extends BaseEvent {
|
|
3
|
+
topic: string;
|
|
4
|
+
raisedAt: Date;
|
|
5
|
+
}
|
|
6
|
+
export interface PublishEvent extends BaseEvent {
|
|
7
|
+
broadcast?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface BaseEvent {
|
|
10
|
+
id: string;
|
|
11
|
+
payload: Record<string, EventData>;
|
|
12
|
+
tenantId: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
stream?: string;
|
|
15
|
+
correlationId?: string;
|
|
16
|
+
causationId?: string;
|
|
17
|
+
reason?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare type EventData = string | GdprEventData;
|
|
20
|
+
export interface GdprEventData {
|
|
21
|
+
value: string;
|
|
22
|
+
gdprDefault: string;
|
|
23
|
+
}
|
|
24
|
+
export declare type HandlerFunc = (event: SubscriptionEvent) => Promise<void>;
|
|
25
|
+
export declare const getSubscriptionEvent: (eventEnvelope: PublishEventEnvelope) => SubscriptionEvent | null;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSubscriptionEvent = void 0;
|
|
4
|
+
const getSubscriptionEvent = (eventEnvelope) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const event = eventEnvelope.event;
|
|
7
|
+
if (!event) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const payload = {};
|
|
11
|
+
for (const key in event.payload) {
|
|
12
|
+
if (Object.prototype.hasOwnProperty.call(event.payload, key)) {
|
|
13
|
+
const data = event.payload[key];
|
|
14
|
+
if (data.metadata && data.metadata.gdpr) {
|
|
15
|
+
payload[key] = {
|
|
16
|
+
value: data.value,
|
|
17
|
+
gdprDefault: (_a = data.metadata.gdpr.default) !== null && _a !== void 0 ? _a : "",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
payload[key] = data.value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
id: event.id,
|
|
27
|
+
topic: eventEnvelope.topic,
|
|
28
|
+
tenantId: eventEnvelope.tenantId,
|
|
29
|
+
payload,
|
|
30
|
+
raisedAt: new Date(event.raisedAt),
|
|
31
|
+
stream: event.stream || undefined,
|
|
32
|
+
type: event.type || undefined,
|
|
33
|
+
causationId: event.causationId || undefined,
|
|
34
|
+
correlationId: event.correlationId || undefined,
|
|
35
|
+
reason: event.reason || undefined,
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
exports.getSubscriptionEvent = getSubscriptionEvent;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Stream } from "./init";
|
|
2
|
+
import { HandlerFunc } from "./event";
|
|
3
|
+
interface EventHandler {
|
|
4
|
+
addHandler: (type: string, handler: HandlerFunc) => void;
|
|
5
|
+
addHandlerForAllTypes: (handler: HandlerFunc) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const initEventHandler: (stream: Stream) => EventHandler;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initEventHandler = void 0;
|
|
4
|
+
const event_1 = require("./event");
|
|
5
|
+
const initEventHandler = (stream) => {
|
|
6
|
+
const typeHandlerMap = {};
|
|
7
|
+
const globalHandlers = [];
|
|
8
|
+
stream.on("data", (data) => {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) !== "event") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const event = (0, event_1.getSubscriptionEvent)(data.data.event);
|
|
14
|
+
if (!event) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const typeHandlers = (_c = typeHandlerMap[(_b = event.type) !== null && _b !== void 0 ? _b : ""]) !== null && _c !== void 0 ? _c : [];
|
|
18
|
+
typeHandlers.forEach(handler => handleEvent(event, handler, stream));
|
|
19
|
+
globalHandlers.forEach(handler => handleEvent(event, handler, stream));
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
addHandler: (type, handler) => {
|
|
23
|
+
if (!typeHandlerMap[type]) {
|
|
24
|
+
typeHandlerMap[type] = [handler];
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
typeHandlerMap[type].push(handler);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
addHandlerForAllTypes: handler => {
|
|
31
|
+
globalHandlers.push(handler);
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
exports.initEventHandler = initEventHandler;
|
|
36
|
+
const handleEvent = (event, handler, stream) => {
|
|
37
|
+
handler(event)
|
|
38
|
+
.then(() => {
|
|
39
|
+
stream.write(newEventAckRequest(event.tenantId, event.topic, event.id));
|
|
40
|
+
})
|
|
41
|
+
.catch(e => {
|
|
42
|
+
stream.write(newEventNotAckRequest(event.tenantId, event.topic, event.id, e));
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const newEventAckRequest = (tenantId, topic, eventId) => {
|
|
46
|
+
return {
|
|
47
|
+
payload: {
|
|
48
|
+
$case: "eventAck",
|
|
49
|
+
eventAck: {
|
|
50
|
+
eventId,
|
|
51
|
+
tenantId,
|
|
52
|
+
topic,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const newEventNotAckRequest = (tenantId, topic, eventId, reason) => {
|
|
58
|
+
return {
|
|
59
|
+
payload: {
|
|
60
|
+
$case: "eventNotAck",
|
|
61
|
+
eventNotAck: {
|
|
62
|
+
eventId,
|
|
63
|
+
tenantId,
|
|
64
|
+
topic,
|
|
65
|
+
reason,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ClientConfig } from "./config";
|
|
2
|
+
import { ClientDuplexStream } from "@grpc/grpc-js";
|
|
3
|
+
import { Request, ServiceClient, Response } from "@fraym/streams-proto";
|
|
4
|
+
export declare type Stream = ClientDuplexStream<Request, Response>;
|
|
5
|
+
export declare const initStream: (config: ClientConfig, serviceClient: ServiceClient) => Promise<Stream>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initStream = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const initStream = async (config, serviceClient) => {
|
|
6
|
+
const stream = serviceClient.connect();
|
|
7
|
+
stream.on("end", stream.end);
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
stream.once("data", (data) => {
|
|
10
|
+
var _a;
|
|
11
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) !== "initAck") {
|
|
12
|
+
reject("connection to streams service was not initialized correctly");
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
resolve(stream);
|
|
16
|
+
});
|
|
17
|
+
stream.write(newInitRequest(config));
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
exports.initStream = initStream;
|
|
21
|
+
const newInitAction = (config) => {
|
|
22
|
+
return {
|
|
23
|
+
groupId: config.groupId,
|
|
24
|
+
subscriberId: (0, uuid_1.v4)(),
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
const newInitRequest = (config) => {
|
|
28
|
+
return {
|
|
29
|
+
payload: {
|
|
30
|
+
$case: "init",
|
|
31
|
+
init: newInitAction(config),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendInvalidateGdpr = void 0;
|
|
4
|
+
const sendInvalidateGdpr = async (tenantId, topic, gdprId, config, stream) => {
|
|
5
|
+
stream.write(newInvalidateGdprRequest(tenantId, topic, gdprId));
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const timeout = setTimeout(() => {
|
|
8
|
+
stream.off("data", fn);
|
|
9
|
+
reject("did not receive invalidate gdpr ack in configured timeout range");
|
|
10
|
+
}, config.ackTimeout);
|
|
11
|
+
const fn = (data) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) === "invalidateGdprNotAck") {
|
|
14
|
+
const notAck = data.data.invalidateGdprNotAck;
|
|
15
|
+
if (notAck.tenantId === tenantId &&
|
|
16
|
+
notAck.topic === topic &&
|
|
17
|
+
notAck.gdprId === gdprId) {
|
|
18
|
+
clearTimeout(timeout);
|
|
19
|
+
stream.off("data", fn);
|
|
20
|
+
reject(`did receive invalidate gdpr not ack message, reason: ${notAck.reason}`);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (((_b = data.data) === null || _b === void 0 ? void 0 : _b.$case) === "invalidateGdprAck") {
|
|
25
|
+
const ack = data.data.invalidateGdprAck;
|
|
26
|
+
if (ack.tenantId === tenantId && ack.topic === topic && ack.gdprId === gdprId) {
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
stream.off("data", fn);
|
|
29
|
+
resolve();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
stream.on("data", fn);
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
exports.sendInvalidateGdpr = sendInvalidateGdpr;
|
|
38
|
+
const newInvalidateGdprRequest = (tenantId, topic, gdprId) => {
|
|
39
|
+
return {
|
|
40
|
+
payload: {
|
|
41
|
+
$case: "invalidateGdpr",
|
|
42
|
+
invalidateGdpr: {
|
|
43
|
+
tenantId,
|
|
44
|
+
topic,
|
|
45
|
+
gdprId,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendPublish = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const sendPublish = async (topic, events, config, stream) => {
|
|
6
|
+
const publishActionId = (0, uuid_1.v4)();
|
|
7
|
+
stream.write(newPublishRequest(publishActionId, topic, events));
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const timeout = setTimeout(() => {
|
|
10
|
+
stream.off("data", fn);
|
|
11
|
+
reject("did not receive publish ack in configured timeout range");
|
|
12
|
+
}, config.ackTimeout);
|
|
13
|
+
const fn = (data) => {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) === "publishAck" &&
|
|
16
|
+
data.data.publishAck.publishActionId === publishActionId) {
|
|
17
|
+
clearTimeout(timeout);
|
|
18
|
+
stream.off("data", fn);
|
|
19
|
+
resolve();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (((_b = data.data) === null || _b === void 0 ? void 0 : _b.$case) === "publishNotAck" &&
|
|
23
|
+
data.data.publishNotAck.publishActionId === publishActionId) {
|
|
24
|
+
clearTimeout(timeout);
|
|
25
|
+
stream.off("data", fn);
|
|
26
|
+
reject(`did receive publish not ack message: ${data.data.publishNotAck.reason}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
stream.on("data", fn);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
exports.sendPublish = sendPublish;
|
|
34
|
+
const newPublishRequest = (publishActionId, topic, events) => {
|
|
35
|
+
return {
|
|
36
|
+
payload: {
|
|
37
|
+
$case: "publish",
|
|
38
|
+
publish: {
|
|
39
|
+
topic,
|
|
40
|
+
publishActionId,
|
|
41
|
+
events: events.map(getEventEnvelopeFromPublishedEvent),
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
const getEventEnvelopeFromPublishedEvent = (event) => {
|
|
47
|
+
var _a, _b, _c, _d, _e, _f;
|
|
48
|
+
const payload = {};
|
|
49
|
+
for (const key in event.payload) {
|
|
50
|
+
const currentData = event.payload[key];
|
|
51
|
+
payload[key] =
|
|
52
|
+
typeof currentData === "string"
|
|
53
|
+
? {
|
|
54
|
+
value: currentData,
|
|
55
|
+
}
|
|
56
|
+
: {
|
|
57
|
+
value: currentData.value,
|
|
58
|
+
metadata: {
|
|
59
|
+
$case: "gdpr",
|
|
60
|
+
gdpr: {
|
|
61
|
+
default: currentData.gdprDefault,
|
|
62
|
+
id: "",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
broadcast: (_a = event.broadcast) !== null && _a !== void 0 ? _a : false,
|
|
69
|
+
tenantId: event.tenantId,
|
|
70
|
+
event: {
|
|
71
|
+
id: event.id,
|
|
72
|
+
type: (_b = event.type) !== null && _b !== void 0 ? _b : "",
|
|
73
|
+
reason: (_c = event.reason) !== null && _c !== void 0 ? _c : "",
|
|
74
|
+
stream: (_d = event.stream) !== null && _d !== void 0 ? _d : "",
|
|
75
|
+
correlationId: (_e = event.correlationId) !== null && _e !== void 0 ? _e : "",
|
|
76
|
+
causationId: (_f = event.causationId) !== null && _f !== void 0 ? _f : "",
|
|
77
|
+
payload,
|
|
78
|
+
raisedAt: "",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendSnapshot = void 0;
|
|
4
|
+
const sendSnapshot = async (topic, toTime, config, stream) => {
|
|
5
|
+
stream.write(newSnapshotRequest(topic, toTime));
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const timeout = setTimeout(() => {
|
|
8
|
+
stream.off("data", fn);
|
|
9
|
+
reject("did not receive snapshot ack in configured timeout range");
|
|
10
|
+
}, config.ackTimeout);
|
|
11
|
+
const fn = (data) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) === "snapshotNotAck" && data.data.snapshotNotAck.topic === topic) {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
stream.off("data", fn);
|
|
16
|
+
reject(`did receive snapshot not ack message, reason: ${data.data.snapshotNotAck.reason}`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (((_b = data.data) === null || _b === void 0 ? void 0 : _b.$case) === "snapshotAck" && data.data.snapshotAck.topic === topic) {
|
|
20
|
+
clearTimeout(timeout);
|
|
21
|
+
stream.off("data", fn);
|
|
22
|
+
resolve();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
stream.on("data", fn);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
exports.sendSnapshot = sendSnapshot;
|
|
30
|
+
const newSnapshotRequest = (topic, toTime) => {
|
|
31
|
+
return {
|
|
32
|
+
payload: {
|
|
33
|
+
$case: "snapshot",
|
|
34
|
+
snapshot: {
|
|
35
|
+
topic,
|
|
36
|
+
toTime: toTime.toISOString(),
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getStream = void 0;
|
|
4
|
+
const event_1 = require("./event");
|
|
5
|
+
const getStream = async (tenantId, stream, serviceClient) => {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
serviceClient.getStream({
|
|
8
|
+
stream,
|
|
9
|
+
tenantId,
|
|
10
|
+
}, (error, response) => {
|
|
11
|
+
if (error) {
|
|
12
|
+
reject(error.message);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
resolve(response.events
|
|
16
|
+
.map(event_1.getSubscriptionEvent)
|
|
17
|
+
.filter(event => event !== null));
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
exports.getStream = getStream;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendSubscribe = void 0;
|
|
4
|
+
const sendSubscribe = async (includedTopics, excludedTopics, config, stream) => {
|
|
5
|
+
stream.write(newSubscribeRequest(includedTopics, excludedTopics));
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const timeout = setTimeout(() => {
|
|
8
|
+
stream.off("data", fn);
|
|
9
|
+
reject("did not receive subscribe ack in configured timeout range");
|
|
10
|
+
}, config.ackTimeout);
|
|
11
|
+
const fn = (data) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (((_a = data.data) === null || _a === void 0 ? void 0 : _a.$case) === "subscribeNotAck") {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
stream.off("data", fn);
|
|
16
|
+
reject(`did receive subscribe not ack message: ${data.data.subscribeNotAck.reason}`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (((_b = data.data) === null || _b === void 0 ? void 0 : _b.$case) === "subscribeAck") {
|
|
20
|
+
clearTimeout(timeout);
|
|
21
|
+
stream.off("data", fn);
|
|
22
|
+
resolve();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
stream.on("data", fn);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
exports.sendSubscribe = sendSubscribe;
|
|
30
|
+
const newSubscribeRequest = (includedTopics, excludedTopics) => {
|
|
31
|
+
return {
|
|
32
|
+
payload: {
|
|
33
|
+
$case: "subscribe",
|
|
34
|
+
subscribe: {
|
|
35
|
+
excludedTopics,
|
|
36
|
+
includedTopics,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./client/client"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fraym/streams",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"homepage": "https://github.com/fraym-work/streams-nodejs",
|
|
6
6
|
"repository": {
|
|
@@ -23,20 +23,16 @@
|
|
|
23
23
|
],
|
|
24
24
|
"main": "dist/index.js",
|
|
25
25
|
"types": "dist/index.d.ts",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@fraym/streams-proto": "^5.3.1",
|
|
28
|
+
"@grpc/grpc-js": "^1.7.2",
|
|
29
|
+
"uuid": "^9.0.0"
|
|
30
|
+
},
|
|
26
31
|
"devDependencies": {
|
|
27
32
|
"@becklyn/prettier": "^1.0.2",
|
|
28
|
-
"@types/google-protobuf": "^3.15.6",
|
|
29
33
|
"@types/uuid": "^8.3.4",
|
|
30
|
-
"grpc_tools_node_protoc_ts": "^5.3.2",
|
|
31
|
-
"grpc-tools": "^1.11.2",
|
|
32
34
|
"prettier": "^2.7.1",
|
|
33
35
|
"typescript": "^4.8.4"
|
|
34
36
|
},
|
|
35
|
-
"prettier": "@becklyn/prettier"
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"@grpc/grpc-js": "^1.7.1",
|
|
38
|
-
"grpc": "^1.24.11",
|
|
39
|
-
"np": "^7.6.2",
|
|
40
|
-
"uuid": "^9.0.0"
|
|
41
|
-
}
|
|
37
|
+
"prettier": "@becklyn/prettier"
|
|
42
38
|
}
|