@furlow/pipes 0.2.1 → 1.0.0

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/index.d.ts CHANGED
@@ -3,5 +3,7 @@ export { WebSocketMessageHandler, WebSocketPipe, WebSocketPipeOptions, createWeb
3
3
  export { WebhookHandler, WebhookPipe, WebhookPipeOptions, WebhookSender, createWebhookPipe } from './webhook/index.js';
4
4
  export { MqttMessageHandler, MqttPipe, MqttPipeOptions, createMqttPipe } from './mqtt/index.js';
5
5
  export { TcpDataHandler, TcpEventHandler, TcpPipe, TcpPipeOptions, UdpEventHandler, UdpMessage, UdpMessageHandler, UdpPipe, UdpPipeOptions, createTcpPipe, createUdpPipe } from './tcp/index.js';
6
- export { H as HttpAuthConfig, a as HttpAuthType, b as HttpPipeConfig, c as HttpRateLimitConfig, M as MqttAuthConfig, d as MqttPipeConfig, e as MqttQoS, P as Pipe, f as PipeResponse, T as TcpPipeConfig, U as UdpPipeConfig, W as WebSocketPipeConfig, g as WebhookPipeConfig, h as WebhookVerification } from './types-BW9r2ksN.js';
6
+ export { DatabaseEventHandler, DatabasePipe, DatabasePipeOptions, createDatabasePipe } from './database/index.js';
7
+ export { FileEventHandler, FilePipe, FilePipeOptions, createFilePipe } from './file/index.js';
8
+ export { D as DatabaseAdapter, a as DatabaseEvent, b as DatabaseEventType, c as DatabasePipeConfig, F as FileEvent, d as FileEventType, e as FilePipeConfig, H as HttpAuthConfig, f as HttpAuthType, g as HttpPipeConfig, h as HttpRateLimitConfig, M as MqttAuthConfig, i as MqttPipeConfig, j as MqttQoS, P as Pipe, k as PipeResponse, T as TcpPipeConfig, U as UdpPipeConfig, W as WebSocketPipeConfig, l as WebhookPipeConfig, m as WebhookVerification } from './types-B6Zdv6jc.js';
7
9
  import 'dgram';
package/dist/index.js CHANGED
@@ -1264,7 +1264,470 @@ var TcpPipe = class {
1264
1264
  function createTcpPipe(options) {
1265
1265
  return new TcpPipe(options);
1266
1266
  }
1267
+
1268
+ // src/database/index.ts
1269
+ var DatabasePipe = class {
1270
+ name;
1271
+ type = "database";
1272
+ config;
1273
+ connected = false;
1274
+ db = null;
1275
+ eventHandlers = /* @__PURE__ */ new Map();
1276
+ constructor(options) {
1277
+ this.name = options.name;
1278
+ this.config = options.config;
1279
+ }
1280
+ /**
1281
+ * Connect to the database
1282
+ */
1283
+ async connect() {
1284
+ if (this.connected) {
1285
+ return;
1286
+ }
1287
+ try {
1288
+ if (this.config.adapter === "sqlite") {
1289
+ const BetterSqlite3 = (await import("better-sqlite3")).default;
1290
+ const connectionString = typeof this.config.connection === "string" ? this.config.connection : ":memory:";
1291
+ this.db = new BetterSqlite3(connectionString);
1292
+ } else if (this.config.adapter === "memory") {
1293
+ this.db = new MemoryDatabase();
1294
+ } else {
1295
+ throw new Error(`Unsupported adapter: ${this.config.adapter}`);
1296
+ }
1297
+ this.connected = true;
1298
+ this.emit("connected", {
1299
+ type: "insert",
1300
+ table: "",
1301
+ data: {}
1302
+ });
1303
+ } catch (error) {
1304
+ const message = error instanceof Error ? error.message : String(error);
1305
+ throw new Error(`Failed to connect to database: ${message}`);
1306
+ }
1307
+ }
1308
+ /**
1309
+ * Disconnect from the database
1310
+ */
1311
+ async disconnect() {
1312
+ if (!this.connected) {
1313
+ return;
1314
+ }
1315
+ try {
1316
+ if (this.config.adapter === "sqlite" && this.db) {
1317
+ this.db.close();
1318
+ }
1319
+ this.db = null;
1320
+ this.connected = false;
1321
+ this.emit("disconnected", {
1322
+ type: "delete",
1323
+ table: "",
1324
+ data: {}
1325
+ });
1326
+ } catch {
1327
+ this.db = null;
1328
+ this.connected = false;
1329
+ }
1330
+ }
1331
+ /**
1332
+ * Check if connected
1333
+ */
1334
+ isConnected() {
1335
+ return this.connected;
1336
+ }
1337
+ /**
1338
+ * Execute a raw SQL query
1339
+ */
1340
+ async query(sql, params = []) {
1341
+ if (!this.isConnected()) {
1342
+ return { success: false, error: "Not connected" };
1343
+ }
1344
+ try {
1345
+ if (this.config.adapter === "sqlite") {
1346
+ const stmt = this.db.prepare(sql);
1347
+ if (sql.trim().toUpperCase().startsWith("SELECT")) {
1348
+ const rows = stmt.all(...params);
1349
+ return { success: true, data: rows };
1350
+ } else {
1351
+ const result = stmt.run(...params);
1352
+ return { success: true, data: result };
1353
+ }
1354
+ } else if (this.config.adapter === "memory") {
1355
+ const result = this.db.query(sql, params);
1356
+ return { success: true, data: result };
1357
+ }
1358
+ return { success: false, error: "Unsupported adapter" };
1359
+ } catch (error) {
1360
+ const message = error instanceof Error ? error.message : String(error);
1361
+ return { success: false, error: message };
1362
+ }
1363
+ }
1364
+ /**
1365
+ * Insert a row into a table
1366
+ */
1367
+ async insert(table, data) {
1368
+ if (!this.isConnected()) {
1369
+ return { success: false, error: "Not connected" };
1370
+ }
1371
+ try {
1372
+ const columns = Object.keys(data);
1373
+ const values = Object.values(data);
1374
+ const placeholders = columns.map(() => "?").join(", ");
1375
+ const sql = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`;
1376
+ let result = {};
1377
+ if (this.config.adapter === "sqlite") {
1378
+ const stmt = this.db.prepare(sql);
1379
+ result = stmt.run(...values);
1380
+ } else if (this.config.adapter === "memory") {
1381
+ result = this.db.insert(table, data);
1382
+ }
1383
+ const event = {
1384
+ type: "insert",
1385
+ table,
1386
+ data
1387
+ };
1388
+ this.emit("insert", event);
1389
+ this.emit("change", event);
1390
+ return { success: true, data: result };
1391
+ } catch (error) {
1392
+ const message = error instanceof Error ? error.message : String(error);
1393
+ return { success: false, error: message };
1394
+ }
1395
+ }
1396
+ /**
1397
+ * Update rows in a table
1398
+ */
1399
+ async update(table, where, data) {
1400
+ if (!this.isConnected()) {
1401
+ return { success: false, error: "Not connected" };
1402
+ }
1403
+ try {
1404
+ const setClauses = Object.keys(data).map((key) => `${key} = ?`).join(", ");
1405
+ const whereClauses = Object.keys(where).map((key) => `${key} = ?`).join(" AND ");
1406
+ const sql = `UPDATE ${table} SET ${setClauses} WHERE ${whereClauses}`;
1407
+ const params = [...Object.values(data), ...Object.values(where)];
1408
+ let result = {};
1409
+ if (this.config.adapter === "sqlite") {
1410
+ const stmt = this.db.prepare(sql);
1411
+ result = stmt.run(...params);
1412
+ } else if (this.config.adapter === "memory") {
1413
+ result = this.db.update(table, where, data);
1414
+ }
1415
+ const event = {
1416
+ type: "update",
1417
+ table,
1418
+ data,
1419
+ oldData: where
1420
+ };
1421
+ this.emit("update", event);
1422
+ this.emit("change", event);
1423
+ return { success: true, data: result };
1424
+ } catch (error) {
1425
+ const message = error instanceof Error ? error.message : String(error);
1426
+ return { success: false, error: message };
1427
+ }
1428
+ }
1429
+ /**
1430
+ * Delete rows from a table
1431
+ */
1432
+ async delete(table, where) {
1433
+ if (!this.isConnected()) {
1434
+ return { success: false, error: "Not connected" };
1435
+ }
1436
+ try {
1437
+ const whereClauses = Object.keys(where).map((key) => `${key} = ?`).join(" AND ");
1438
+ const sql = `DELETE FROM ${table} WHERE ${whereClauses}`;
1439
+ const params = Object.values(where);
1440
+ let result = {};
1441
+ if (this.config.adapter === "sqlite") {
1442
+ const stmt = this.db.prepare(sql);
1443
+ result = stmt.run(...params);
1444
+ } else if (this.config.adapter === "memory") {
1445
+ result = this.db.delete(table, where);
1446
+ }
1447
+ const event = {
1448
+ type: "delete",
1449
+ table,
1450
+ data: where
1451
+ };
1452
+ this.emit("delete", event);
1453
+ this.emit("change", event);
1454
+ return { success: true, data: result };
1455
+ } catch (error) {
1456
+ const message = error instanceof Error ? error.message : String(error);
1457
+ return { success: false, error: message };
1458
+ }
1459
+ }
1460
+ /**
1461
+ * Register an event handler
1462
+ */
1463
+ on(event, handler) {
1464
+ const handlers = this.eventHandlers.get(event) ?? [];
1465
+ handlers.push(handler);
1466
+ this.eventHandlers.set(event, handlers);
1467
+ }
1468
+ /**
1469
+ * Remove an event handler
1470
+ */
1471
+ off(event, handler) {
1472
+ const handlers = this.eventHandlers.get(event) ?? [];
1473
+ const index = handlers.indexOf(handler);
1474
+ if (index !== -1) {
1475
+ handlers.splice(index, 1);
1476
+ }
1477
+ }
1478
+ /**
1479
+ * Emit an event
1480
+ */
1481
+ emit(event, data) {
1482
+ const handlers = this.eventHandlers.get(event) ?? [];
1483
+ for (const handler of handlers) {
1484
+ try {
1485
+ handler(data);
1486
+ } catch (error) {
1487
+ console.error(`Database handler error for "${event}":`, error);
1488
+ }
1489
+ }
1490
+ }
1491
+ };
1492
+ var MemoryDatabase = class {
1493
+ tables = /* @__PURE__ */ new Map();
1494
+ autoIncrements = /* @__PURE__ */ new Map();
1495
+ query(sql, _params) {
1496
+ const selectMatch = sql.match(/SELECT \* FROM (\w+)/i);
1497
+ if (selectMatch) {
1498
+ const table = selectMatch[1];
1499
+ return this.tables.get(table) ?? [];
1500
+ }
1501
+ return [];
1502
+ }
1503
+ insert(table, data) {
1504
+ if (!this.tables.has(table)) {
1505
+ this.tables.set(table, []);
1506
+ }
1507
+ const id = (this.autoIncrements.get(table) ?? 0) + 1;
1508
+ this.autoIncrements.set(table, id);
1509
+ const row = { id, ...data };
1510
+ this.tables.get(table).push(row);
1511
+ return { lastInsertRowid: id };
1512
+ }
1513
+ update(table, where, data) {
1514
+ const rows = this.tables.get(table) ?? [];
1515
+ let changes = 0;
1516
+ for (const row of rows) {
1517
+ if (this.matchesWhere(row, where)) {
1518
+ Object.assign(row, data);
1519
+ changes++;
1520
+ }
1521
+ }
1522
+ return { changes };
1523
+ }
1524
+ delete(table, where) {
1525
+ const rows = this.tables.get(table) ?? [];
1526
+ const initialLength = rows.length;
1527
+ const remaining = rows.filter((row) => !this.matchesWhere(row, where));
1528
+ this.tables.set(table, remaining);
1529
+ return { changes: initialLength - remaining.length };
1530
+ }
1531
+ matchesWhere(row, where) {
1532
+ for (const [key, value] of Object.entries(where)) {
1533
+ if (row[key] !== value) {
1534
+ return false;
1535
+ }
1536
+ }
1537
+ return true;
1538
+ }
1539
+ };
1540
+ function createDatabasePipe(options) {
1541
+ return new DatabasePipe(options);
1542
+ }
1543
+
1544
+ // src/file/index.ts
1545
+ import chokidar from "chokidar";
1546
+ var FilePipe = class {
1547
+ name;
1548
+ type = "file";
1549
+ watcher = null;
1550
+ config;
1551
+ watching = false;
1552
+ eventHandlers = /* @__PURE__ */ new Map();
1553
+ constructor(options) {
1554
+ this.name = options.name;
1555
+ this.config = options.config;
1556
+ }
1557
+ /**
1558
+ * Start watching files (alias for connect)
1559
+ */
1560
+ async watch() {
1561
+ return this.connect();
1562
+ }
1563
+ /**
1564
+ * Start watching files
1565
+ */
1566
+ async connect() {
1567
+ if (this.watching) {
1568
+ return;
1569
+ }
1570
+ return new Promise((resolve, reject) => {
1571
+ try {
1572
+ this.watcher = chokidar.watch(this.config.paths, {
1573
+ ignored: this.config.ignore,
1574
+ persistent: this.config.persistent ?? true,
1575
+ usePolling: this.config.usePolling ?? false,
1576
+ ignoreInitial: true
1577
+ });
1578
+ this.watcher.on("ready", () => {
1579
+ this.watching = true;
1580
+ resolve();
1581
+ });
1582
+ this.watcher.on("error", (error) => {
1583
+ if (!this.watching) {
1584
+ reject(error);
1585
+ }
1586
+ this.emit("error", {
1587
+ type: "change",
1588
+ path: ""
1589
+ });
1590
+ });
1591
+ this.watcher.on("add", (path, stats) => {
1592
+ const event = {
1593
+ type: "add",
1594
+ path,
1595
+ stats: stats ? {
1596
+ size: stats.size,
1597
+ mtime: stats.mtime,
1598
+ isDirectory: stats.isDirectory()
1599
+ } : void 0
1600
+ };
1601
+ this.emit("add", event);
1602
+ this.emit("all", event);
1603
+ });
1604
+ this.watcher.on("change", (path, stats) => {
1605
+ const event = {
1606
+ type: "change",
1607
+ path,
1608
+ stats: stats ? {
1609
+ size: stats.size,
1610
+ mtime: stats.mtime,
1611
+ isDirectory: stats.isDirectory()
1612
+ } : void 0
1613
+ };
1614
+ this.emit("change", event);
1615
+ this.emit("all", event);
1616
+ });
1617
+ this.watcher.on("unlink", (path) => {
1618
+ const event = {
1619
+ type: "unlink",
1620
+ path
1621
+ };
1622
+ this.emit("unlink", event);
1623
+ this.emit("all", event);
1624
+ });
1625
+ this.watcher.on("addDir", (path, stats) => {
1626
+ const event = {
1627
+ type: "addDir",
1628
+ path,
1629
+ stats: stats ? {
1630
+ size: stats.size,
1631
+ mtime: stats.mtime,
1632
+ isDirectory: true
1633
+ } : void 0
1634
+ };
1635
+ this.emit("addDir", event);
1636
+ this.emit("all", event);
1637
+ });
1638
+ this.watcher.on("unlinkDir", (path) => {
1639
+ const event = {
1640
+ type: "unlinkDir",
1641
+ path
1642
+ };
1643
+ this.emit("unlinkDir", event);
1644
+ this.emit("all", event);
1645
+ });
1646
+ } catch (error) {
1647
+ reject(error);
1648
+ }
1649
+ });
1650
+ }
1651
+ /**
1652
+ * Stop watching files
1653
+ */
1654
+ async disconnect() {
1655
+ if (!this.watcher) {
1656
+ return;
1657
+ }
1658
+ await this.watcher.close();
1659
+ this.watcher = null;
1660
+ this.watching = false;
1661
+ }
1662
+ /**
1663
+ * Check if watching
1664
+ */
1665
+ isConnected() {
1666
+ return this.watching;
1667
+ }
1668
+ /**
1669
+ * Add paths to watch
1670
+ */
1671
+ add(paths) {
1672
+ if (this.watcher) {
1673
+ this.watcher.add(paths);
1674
+ }
1675
+ }
1676
+ /**
1677
+ * Stop watching specific paths
1678
+ */
1679
+ unwatch(paths) {
1680
+ if (this.watcher) {
1681
+ this.watcher.unwatch(paths);
1682
+ }
1683
+ }
1684
+ /**
1685
+ * Get watched paths
1686
+ */
1687
+ getWatched() {
1688
+ if (this.watcher) {
1689
+ return this.watcher.getWatched();
1690
+ }
1691
+ return {};
1692
+ }
1693
+ /**
1694
+ * Register an event handler
1695
+ */
1696
+ on(event, handler) {
1697
+ const handlers = this.eventHandlers.get(event) ?? [];
1698
+ handlers.push(handler);
1699
+ this.eventHandlers.set(event, handlers);
1700
+ }
1701
+ /**
1702
+ * Remove an event handler
1703
+ */
1704
+ off(event, handler) {
1705
+ const handlers = this.eventHandlers.get(event) ?? [];
1706
+ const index = handlers.indexOf(handler);
1707
+ if (index !== -1) {
1708
+ handlers.splice(index, 1);
1709
+ }
1710
+ }
1711
+ /**
1712
+ * Emit an event
1713
+ */
1714
+ emit(event, data) {
1715
+ const handlers = this.eventHandlers.get(event) ?? [];
1716
+ for (const handler of handlers) {
1717
+ try {
1718
+ handler(data);
1719
+ } catch (error) {
1720
+ console.error(`File handler error for "${event}":`, error);
1721
+ }
1722
+ }
1723
+ }
1724
+ };
1725
+ function createFilePipe(options) {
1726
+ return new FilePipe(options);
1727
+ }
1267
1728
  export {
1729
+ DatabasePipe,
1730
+ FilePipe,
1268
1731
  HttpPipe,
1269
1732
  MqttPipe,
1270
1733
  TcpPipe,
@@ -1272,6 +1735,8 @@ export {
1272
1735
  WebSocketPipe,
1273
1736
  WebhookPipe,
1274
1737
  WebhookSender,
1738
+ createDatabasePipe,
1739
+ createFilePipe,
1275
1740
  createHttpPipe,
1276
1741
  createMqttPipe,
1277
1742
  createTcpPipe,