pulse-sdk 0.0.1

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 ADDED
@@ -0,0 +1,111 @@
1
+ # Pulse SDK — TypeScript
2
+
3
+ TypeScript client for Pulse Broker (gRPC). This README is written for end users and explains installation, configuration, and basic usage with practical examples.
4
+
5
+ ## Installation
6
+
7
+ Install from npm (published package):
8
+
9
+ ```bash
10
+ npm install pulse-sdk
11
+ ```
12
+
13
+ Or install locally from the repository (for development):
14
+
15
+ ```bash
16
+ npm install
17
+ ```
18
+
19
+ To compile the TypeScript sources (optional for development/CI):
20
+
21
+ ```bash
22
+ npm run build
23
+ ```
24
+
25
+ Run the lightweight integration tests (a test gRPC server is started automatically):
26
+
27
+ ```bash
28
+ npm test
29
+ ```
30
+
31
+ ## Configuration (current)
32
+
33
+ Currently the SDK supports programmatic configuration only: create and pass a `PulseConfig` object when instantiating `Producer` or `Consumer`.
34
+
35
+ The code exposes a `PulseConfig` interface for strong typing. Environment-file loading (e.g. `pulse.yml` or `PULSE_*` environment variables) is planned but not implemented in this initial version — for now, pass configuration directly in code.
36
+
37
+ ## Quick Start
38
+
39
+ Import from the published package and pass configuration programmatically:
40
+
41
+ ```ts
42
+ import { Producer, Consumer } from 'pulse-sdk';
43
+
44
+ const cfg = { grpcUrl: 'localhost:50052', eventTypes: ['events'] };
45
+
46
+ // Send a JSON-serializable event
47
+ const producer = new Producer(cfg);
48
+ await producer.send('events', { type: 'user.created', id: 123 });
49
+
50
+ // Consume events and register a handler
51
+ const consumer = new Consumer(cfg);
52
+ consumer.on('events', (msg) => {
53
+ console.log('received', msg.payload);
54
+ });
55
+ await consumer.start('events', 'my-consumer');
56
+ ```
57
+
58
+ ### Programmatic override
59
+
60
+ You can create and pass `PulseConfig` directly in code:
61
+
62
+ ```ts
63
+ const cfg = { grpcUrl: '10.0.0.5:50052', eventTypes: ['events'] };
64
+ const producer = new Producer(cfg);
65
+ ```
66
+
67
+ ## Technical Details
68
+
69
+ - The SDK dynamically loads `pulse.proto` at runtime using `@grpc/proto-loader` and `@grpc/grpc-js`.
70
+ - The protobuf field `bytes payload` is used to carry the message body; the SDK serializes JSON payloads into that field by default.
71
+ - `Consumer.start()` opens a server stream (`Consume`) and dispatches incoming messages to handlers registered via `consumer.on(topic, handler)`.
72
+
73
+ ## Examples
74
+
75
+ Producer (send multiple events):
76
+
77
+ ```ts
78
+ const producer = new Producer(loadConfig());
79
+ await producer.send('events', { type: 'login', userId: 1 });
80
+ await producer.send('events', { type: 'logout', userId: 1 });
81
+ ```
82
+
83
+ Consumer (simple processing):
84
+
85
+ ```ts
86
+ const cfg = loadConfig();
87
+ const consumer = new Consumer(cfg);
88
+
89
+ consumer.on('events', (msg) => {
90
+ console.log('event payload', msg.payload);
91
+ });
92
+
93
+ await consumer.start('events', cfg.consumerName || 'default');
94
+ ```
95
+
96
+ ## Local Tests
97
+
98
+ The tests in `tests/` start a lightweight gRPC test server automatically; run them with `npm test`.
99
+
100
+ ## FAQ (short)
101
+
102
+ - Can I use decorators for handlers? Yes — TypeScript supports decorators, but this SDK does not use them by default. We can add decorator helpers later if desired.
103
+ - How do I enable TLS / secure credentials? The client factory currently uses `createInsecure()` by default. We can expose a `credentials` option on `PulseConfig` to accept `grpc.credentials.createSsl(...)` or other credential objects.
104
+
105
+ ## Contributing
106
+
107
+ Please open a PR with tests. The existing tests validate basic Producer/Consumer behaviour.
108
+
109
+ ---
110
+
111
+ If you want this README expanded to mirror the Python SDK more closely (topic-level config, manual offset commits, longer examples), tell me which sections to add and I will update it.
@@ -0,0 +1,5 @@
1
+ export interface PulseConfig {
2
+ grpcUrl: string;
3
+ eventTypes: string[];
4
+ }
5
+ export declare function loadConfig(config: PulseConfig): PulseConfig;
package/dist/config.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ function loadConfig(config) {
5
+ // Aqui pode ser expandido para ler de arquivo ou env
6
+ return config;
7
+ }
@@ -0,0 +1,10 @@
1
+ import { PulseConfig } from './config';
2
+ export type EventHandler = (payload: any) => void;
3
+ export declare class Consumer {
4
+ private config;
5
+ private handlers;
6
+ private client;
7
+ constructor(config: PulseConfig);
8
+ on(eventType: string, handler: EventHandler): void;
9
+ start(topic?: string, consumerName?: string): Promise<void>;
10
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Consumer = void 0;
4
+ const client_1 = require("./proto/client");
5
+ class Consumer {
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.handlers = {};
9
+ this.client = (0, client_1.createClient)(config.grpcUrl);
10
+ }
11
+ on(eventType, handler) {
12
+ if (!this.handlers[eventType]) {
13
+ this.handlers[eventType] = [];
14
+ }
15
+ this.handlers[eventType].push(handler);
16
+ }
17
+ async start(topic, consumerName = 'default') {
18
+ const req = { topic: topic || this.config.eventTypes[0], consumer_name: consumerName, offset: 0 };
19
+ const stream = this.client.Consume(req);
20
+ stream.on('data', (msg) => {
21
+ const payloadBuf = msg.payload;
22
+ let parsed = payloadBuf;
23
+ try {
24
+ parsed = JSON.parse(payloadBuf.toString());
25
+ }
26
+ catch (e) {
27
+ // keep raw buffer if not JSON
28
+ }
29
+ const handlers = this.handlers[req.topic] || [];
30
+ handlers.forEach(h => h({ offset: msg.offset, timestamp: msg.timestamp, payload: parsed, headers: msg.headers }));
31
+ });
32
+ return new Promise((resolve, reject) => {
33
+ stream.on('end', () => resolve());
34
+ stream.on('error', (e) => reject(e));
35
+ });
36
+ }
37
+ }
38
+ exports.Consumer = Consumer;
@@ -0,0 +1,3 @@
1
+ export * from './producer';
2
+ export * from './consumer';
3
+ export * from './config';
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
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("./producer"), exports);
18
+ __exportStar(require("./consumer"), exports);
19
+ __exportStar(require("./config"), exports);
@@ -0,0 +1,11 @@
1
+ import { PulseConfig } from './config';
2
+ export interface PublishResponse {
3
+ id: string;
4
+ offset: number | string;
5
+ }
6
+ export declare class Producer {
7
+ private config;
8
+ private client;
9
+ constructor(config: PulseConfig);
10
+ send(topic: string, payload: any, headers?: Record<string, string>): Promise<PublishResponse>;
11
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Producer = void 0;
4
+ const client_1 = require("./proto/client");
5
+ class Producer {
6
+ constructor(config) {
7
+ this.config = config;
8
+ this.client = (0, client_1.createClient)(config.grpcUrl);
9
+ }
10
+ async send(topic, payload, headers) {
11
+ const req = {
12
+ topic,
13
+ payload: Buffer.from(JSON.stringify(payload)),
14
+ headers: headers || {},
15
+ };
16
+ return new Promise((resolve, reject) => {
17
+ this.client.Publish(req, (err, res) => {
18
+ if (err)
19
+ return reject(err);
20
+ resolve({ id: res.id, offset: res.offset });
21
+ });
22
+ });
23
+ }
24
+ }
25
+ exports.Producer = Producer;
@@ -0,0 +1,2 @@
1
+ export type PulseClient = any;
2
+ export declare function createClient(address: string): PulseClient;
@@ -0,0 +1,54 @@
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.createClient = createClient;
40
+ const path_1 = __importDefault(require("path"));
41
+ const grpc = __importStar(require("@grpc/grpc-js"));
42
+ const protoLoader = __importStar(require("@grpc/proto-loader"));
43
+ const PROTO_PATH = path_1.default.resolve(__dirname, '../../../../internal/api/proto/pulse.proto');
44
+ const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
45
+ keepCase: true,
46
+ longs: String,
47
+ enums: String,
48
+ defaults: true,
49
+ oneofs: true,
50
+ });
51
+ const loaded = grpc.loadPackageDefinition(packageDefinition).pulse.v1;
52
+ function createClient(address) {
53
+ return new loaded.PulseService(address, grpc.credentials.createInsecure());
54
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "pulse-sdk",
3
+ "version": "0.0.1",
4
+ "description": "Pulse SDK for Node.js/TypeScript",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "jest"
10
+ },
11
+ "author": "",
12
+ "license": "MIT",
13
+ "files": [
14
+ "dist",
15
+ "README.md"
16
+ ],
17
+ "prepare": "npm run build",
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "devDependencies": {
22
+ "typescript": "^5.0.0",
23
+ "jest": "^29.0.0",
24
+ "ts-jest": "^29.0.0",
25
+ "@types/jest": "^29.0.0"
26
+ },
27
+ "dependencies": {
28
+ "@grpc/grpc-js": "^1.8.0",
29
+ "protobufjs": "^7.2.0",
30
+ "@grpc/proto-loader": "^0.7.0"
31
+ },
32
+ "jest": {
33
+ "preset": "ts-jest",
34
+ "testEnvironment": "node",
35
+ "testMatch": [
36
+ "**/tests/**/*.test.ts"
37
+ ]
38
+ }
39
+ }