@linkforty/core 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 LinkForty
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,459 @@
1
+ # @linkforty/core
2
+
3
+ **Open-source deeplink management engine with device detection and analytics**
4
+
5
+ LinkForty Core is a powerful, self-hosted deeplink management system that enables you to create, manage, and track smart links with device-specific routing, analytics, and UTM parameter support. It's the open-source foundation of the LinkForty platform.
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@linkforty/core.svg)](https://www.npmjs.com/package/@linkforty/core)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
9
+
10
+ ## Features
11
+
12
+ ✅ **Smart Link Routing** - Create short links with device-specific URLs for iOS, Android, and web \
13
+ ✅ **Device Detection** - Automatic detection and routing based on user device \
14
+ ✅ **Click Analytics** - Track clicks with geolocation, device type, platform, and more \
15
+ ✅ **UTM Parameters** - Built-in support for UTM campaign tracking \
16
+ ✅ **Link Expiration** - Set expiration dates for time-sensitive links \
17
+ ✅ **Redis Caching** - Optional Redis support for high-performance link lookups \
18
+ ✅ **PostgreSQL Storage** - Reliable data persistence with full SQL capabilities \
19
+ ✅ **TypeScript** - Fully typed API for better developer experience
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @linkforty/core
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Basic Server
30
+
31
+ ```typescript
32
+ import { createServer } from '@linkforty/core';
33
+
34
+ async function start() {
35
+ const server = await createServer({
36
+ database: {
37
+ url: 'postgresql://localhost/linkforty',
38
+ },
39
+ redis: {
40
+ url: 'redis://localhost:6379',
41
+ },
42
+ });
43
+
44
+ await server.listen({ port: 3000, host: '0.0.0.0' });
45
+ console.log('Server running on http://localhost:3000');
46
+ }
47
+
48
+ start();
49
+ ```
50
+
51
+ ### 2. Self-Hosting with Docker
52
+
53
+ ```bash
54
+ # Clone the examples
55
+ git clone https://github.com/linkforty/core.git
56
+ cd core/examples
57
+
58
+ # Start services
59
+ docker-compose up -d
60
+
61
+ # Server will be available at http://localhost:3000
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### Create a Link
67
+
68
+ ```bash
69
+ POST /api/links
70
+ Content-Type: application/json
71
+
72
+ {
73
+ "userId": "user-uuid",
74
+ "originalUrl": "https://example.com",
75
+ "title": "My Link",
76
+ "iosUrl": "myapp://product/123",
77
+ "androidUrl": "myapp://product/123",
78
+ "webFallbackUrl": "https://example.com/product/123",
79
+ "utmParameters": {
80
+ "source": "twitter",
81
+ "medium": "social",
82
+ "campaign": "summer-sale"
83
+ },
84
+ "customCode": "summer-sale",
85
+ "expiresAt": "2024-12-31T23:59:59Z"
86
+ }
87
+ ```
88
+
89
+ **Response:**
90
+
91
+ ```json
92
+ {
93
+ "id": "link-uuid",
94
+ "userId": "user-uuid",
95
+ "short_code": "summer-sale",
96
+ "original_url": "https://example.com",
97
+ "title": "My Link",
98
+ "ios_url": "myapp://product/123",
99
+ "android_url": "myapp://product/123",
100
+ "web_fallback_url": "https://example.com/product/123",
101
+ "utmParameters": {
102
+ "source": "twitter",
103
+ "medium": "social",
104
+ "campaign": "summer-sale"
105
+ },
106
+ "is_active": true,
107
+ "expires_at": "2024-12-31T23:59:59Z",
108
+ "created_at": "2024-01-01T00:00:00Z",
109
+ "updated_at": "2024-01-01T00:00:00Z",
110
+ "clickCount": 0
111
+ }
112
+ ```
113
+
114
+ ### Get All Links
115
+
116
+ ```bash
117
+ GET /api/links?userId=user-uuid
118
+ ```
119
+
120
+ ### Get a Specific Link
121
+
122
+ ```bash
123
+ GET /api/links/:id?userId=user-uuid
124
+ ```
125
+
126
+ ### Update a Link
127
+
128
+ ```bash
129
+ PUT /api/links/:id?userId=user-uuid
130
+ Content-Type: application/json
131
+
132
+ {
133
+ "title": "Updated Title",
134
+ "isActive": false
135
+ }
136
+ ```
137
+
138
+ ### Delete a Link
139
+
140
+ ```bash
141
+ DELETE /api/links/:id?userId=user-uuid
142
+ ```
143
+
144
+ ### Get Analytics Overview
145
+
146
+ ```bash
147
+ GET /api/analytics/overview?userId=user-uuid&days=30
148
+ ```
149
+
150
+ **Response:**
151
+
152
+ ```json
153
+ {
154
+ "totalClicks": 1234,
155
+ "uniqueClicks": 567,
156
+ "clicksByDate": [
157
+ { "date": "2024-01-01", "clicks": 45 }
158
+ ],
159
+ "clicksByCountry": [
160
+ { "countryCode": "US", "country": "United States", "clicks": 234 }
161
+ ],
162
+ "clicksByDevice": [
163
+ { "device": "mobile", "clicks": 789 }
164
+ ],
165
+ "clicksByPlatform": [
166
+ { "platform": "iOS", "clicks": 456 }
167
+ ],
168
+ "topLinks": [
169
+ {
170
+ "id": "link-uuid",
171
+ "shortCode": "summer-sale",
172
+ "title": "My Link",
173
+ "originalUrl": "https://example.com",
174
+ "totalClicks": 123,
175
+ "uniqueClicks": 67
176
+ }
177
+ ]
178
+ }
179
+ ```
180
+
181
+ ### Get Link-Specific Analytics
182
+
183
+ ```bash
184
+ GET /api/analytics/links/:linkId?userId=user-uuid&days=30
185
+ ```
186
+
187
+ ### Redirect Short Link
188
+
189
+ ```bash
190
+ GET /:shortCode
191
+ ```
192
+
193
+ This endpoint automatically redirects users to the appropriate URL based on their device type.
194
+
195
+ ## Configuration
196
+
197
+ ### Server Options
198
+
199
+ ```typescript
200
+ interface ServerOptions {
201
+ database?: {
202
+ url?: string; // PostgreSQL connection string
203
+ pool?: {
204
+ min?: number; // Minimum pool connections (default: 2)
205
+ max?: number; // Maximum pool connections (default: 10)
206
+ };
207
+ };
208
+ redis?: {
209
+ url: string; // Redis connection string (optional)
210
+ };
211
+ cors?: {
212
+ origin: string | string[]; // CORS allowed origins (default: '*')
213
+ };
214
+ logger?: boolean; // Enable Fastify logger (default: true)
215
+ }
216
+ ```
217
+
218
+ ### Environment Variables
219
+
220
+ ```bash
221
+ DATABASE_URL=postgresql://localhost/linkforty
222
+ REDIS_URL=redis://localhost:6379
223
+ PORT=3000
224
+ NODE_ENV=production
225
+ CORS_ORIGIN=*
226
+ ```
227
+
228
+ ## Database Schema
229
+
230
+ ### Users Table
231
+
232
+ | Column | Type | Description |
233
+ |---------------|--------------|-----------------------|
234
+ | id | UUID | Primary key |
235
+ | email | VARCHAR(255) | Unique email |
236
+ | name | VARCHAR(255) | User name |
237
+ | password_hash | VARCHAR(255) | Hashed password |
238
+ | created_at | TIMESTAMP | Creation timestamp |
239
+ | updated_at | TIMESTAMP | Last update timestamp |
240
+
241
+ ### Links Table
242
+
243
+ | Column | Type | Description |
244
+ |------------------|--------------|-----------------------|
245
+ | id | UUID | Primary key |
246
+ | user_id | UUID | Foreign key to users |
247
+ | short_code | VARCHAR(20) | Unique short code |
248
+ | original_url | TEXT | Original URL |
249
+ | title | VARCHAR(255) | Link title |
250
+ | ios_url | TEXT | iOS-specific URL |
251
+ | android_url | TEXT | Android-specific URL |
252
+ | web_fallback_url | TEXT | Web fallback URL |
253
+ | utm_parameters | JSONB | UTM parameters |
254
+ | targeting_rules | JSONB | Targeting rules |
255
+ | is_active | BOOLEAN | Active status |
256
+ | expires_at | TIMESTAMP | Expiration date |
257
+ | created_at | TIMESTAMP | Creation timestamp |
258
+ | updated_at | TIMESTAMP | Last update timestamp |
259
+
260
+ ### Click Events Table
261
+
262
+ | Column | Type | Description |
263
+ |--------------|--------------|------------------------------|
264
+ | id | UUID | Primary key |
265
+ | link_id | UUID | Foreign key to links |
266
+ | clicked_at | TIMESTAMP | Click timestamp |
267
+ | ip_address | INET | User IP address |
268
+ | user_agent | TEXT | User agent string |
269
+ | device_type | VARCHAR(20) | Device type (mobile/desktop) |
270
+ | platform | VARCHAR(20) | Platform (iOS/Android/Web) |
271
+ | country_code | CHAR(2) | Country code |
272
+ | country_name | VARCHAR(100) | Country name |
273
+ | region | VARCHAR(100) | Region/state |
274
+ | city | VARCHAR(100) | City |
275
+ | latitude | DECIMAL | Latitude |
276
+ | longitude | DECIMAL | Longitude |
277
+ | timezone | VARCHAR(100) | Timezone |
278
+ | utm_source | VARCHAR(255) | UTM source |
279
+ | utm_medium | VARCHAR(255) | UTM medium |
280
+ | utm_campaign | VARCHAR(255) | UTM campaign |
281
+ | referrer | TEXT | Referrer URL |
282
+
283
+ ## Utilities
284
+
285
+ ### Generate Short Code
286
+
287
+ ```typescript
288
+ import { generateShortCode } from '@linkforty/core';
289
+
290
+ const code = generateShortCode(8); // Returns 8-character nanoid
291
+ ```
292
+
293
+ ### Detect Device
294
+
295
+ ```typescript
296
+ import { detectDevice } from '@linkforty/core';
297
+
298
+ const device = detectDevice(userAgent); // Returns 'ios' | 'android' | 'web'
299
+ ```
300
+
301
+ ### Get Location from IP
302
+
303
+ ```typescript
304
+ import { getLocationFromIP } from '@linkforty/core';
305
+
306
+ const location = getLocationFromIP('8.8.8.8');
307
+ // Returns: { countryCode, countryName, region, city, latitude, longitude, timezone }
308
+ ```
309
+
310
+ ### Build Redirect URL with UTM Parameters
311
+
312
+ ```typescript
313
+ import { buildRedirectUrl } from '@linkforty/core';
314
+
315
+ const url = buildRedirectUrl('https://example.com', {
316
+ source: 'twitter',
317
+ medium: 'social',
318
+ campaign: 'summer-sale'
319
+ });
320
+ // Returns: https://example.com?utm_source=twitter&utm_medium=social&utm_campaign=summer-sale
321
+ ```
322
+
323
+ ## Advanced Usage
324
+
325
+ ### Custom Route Registration
326
+
327
+ ```typescript
328
+ import { createServer } from '@linkforty/core';
329
+
330
+ const server = await createServer({
331
+ database: { url: 'postgresql://localhost/linkforty' },
332
+ });
333
+
334
+ // Add custom routes
335
+ server.get('/custom', async (request, reply) => {
336
+ return { message: 'Hello World' };
337
+ });
338
+
339
+ await server.listen({ port: 3000 });
340
+ ```
341
+
342
+ ### Using Individual Route Handlers
343
+
344
+ ```typescript
345
+ import Fastify from 'fastify';
346
+ import { initializeDatabase, redirectRoutes, linkRoutes } from '@linkforty/core';
347
+
348
+ const fastify = Fastify();
349
+
350
+ // Initialize database separately
351
+ await initializeDatabase({ url: 'postgresql://localhost/linkforty' });
352
+
353
+ // Register only specific routes
354
+ await fastify.register(redirectRoutes);
355
+ await fastify.register(linkRoutes);
356
+
357
+ await fastify.listen({ port: 3000 });
358
+ ```
359
+
360
+ ## Deployment
361
+
362
+ LinkForty can be deployed in multiple ways depending on your needs:
363
+
364
+ ### 🚀 Production Deployment (Recommended)
365
+
366
+ Deploy to managed platforms with minimal DevOps overhead:
367
+
368
+ **Fly.io (Recommended)**
369
+ - Global edge deployment
370
+ - Managed PostgreSQL and Redis
371
+ - Auto-scaling and SSL included
372
+ - Starting at ~$10-15/month
373
+
374
+ [View Fly.io deployment guide →](infra/fly.io/DEPLOYMENT.md)
375
+
376
+ See [`infra/`](infra/) directory for all deployment options and platform-specific guides.
377
+
378
+ ### Docker Deployment (Self-Hosted)
379
+
380
+ For local development or self-managed infrastructure:
381
+
382
+ ```bash
383
+ git clone https://github.com/linkforty/core.git
384
+ cd core/examples
385
+ docker-compose up -d
386
+ ```
387
+
388
+ See [`examples/docker-compose.yml`](examples/docker-compose.yml) for complete Docker setup.
389
+
390
+ ### Manual Deployment
391
+
392
+ For custom infrastructure needs:
393
+
394
+ 1. Install dependencies: `npm install @linkforty/core`
395
+ 2. Set up PostgreSQL database (13+)
396
+ 3. Set up Redis (optional but recommended)
397
+ 4. Run migrations: `npm run migrate`
398
+ 5. Start server: `node server.js`
399
+
400
+ ### Other Platforms
401
+
402
+ Community-maintained templates available for:
403
+ - AWS (ECS/Fargate)
404
+ - Google Cloud Run
405
+ - Railway, Render, and more
406
+
407
+ See [`infra/CONTRIBUTING.md`](infra/CONTRIBUTING.md) to add support for additional platforms.
408
+
409
+ ## Performance
410
+
411
+ - **Redis caching**: 5-minute TTL on link lookups reduces database queries by 90%
412
+ - **Database indexes**: Optimized queries for fast link lookups and analytics
413
+ - **Async click tracking**: Non-blocking click event logging
414
+ - **Connection pooling**: Efficient database connection management
415
+
416
+ ## Security
417
+
418
+ - **SQL injection protection**: Parameterized queries throughout
419
+ - **Input validation**: Zod schema validation on all inputs
420
+ - **CORS configuration**: Configurable CORS for API access control
421
+ - **Link expiration**: Automatic handling of expired links
422
+
423
+ ## Roadmap
424
+
425
+ - [ ] Webhook support for click events
426
+ - [ ] Bulk link operations via API
427
+ - [ ] Link grouping and tags
428
+ - [ ] A/B testing support
429
+ - [ ] QR code generation
430
+ - [ ] Custom domain support (in SaaS version)
431
+
432
+ ## Contributing
433
+
434
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
435
+
436
+ ## License
437
+
438
+ MIT License - see [LICENSE](LICENSE) file for details.
439
+
440
+ ## Related Projects
441
+
442
+ - **@linkforty/ui** - React UI components for link management
443
+ - **[LinkForty Cloud](https://linkforty.com)** - Hosted SaaS version with additional features
444
+
445
+ ## Support
446
+
447
+ - **Documentation**: [https://docs.linkforty.com](https://docs.linkforty.com)
448
+ - **Issues**: [GitHub Issues](https://github.com/linkforty/core/issues)
449
+ - **Discussions**: [GitHub Discussions](https://github.com/linkforty/core/discussions)
450
+
451
+ ## Built with:
452
+ - [Fastify](https://www.fastify.io/) - Fast web framework
453
+ - [PostgreSQL](https://www.postgresql.org/) - Powerful database
454
+ - [Redis](https://redis.io/) - In-memory cache
455
+ - [nanoid](https://github.com/ai/nanoid) - Unique ID generation
456
+ - [geoip-lite](https://github.com/geoip-lite/node-geoip) - IP geolocation
457
+ - [ua-parser-js](https://github.com/faisalman/ua-parser-js) - User agent parsing
458
+
459
+
@@ -0,0 +1,18 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import { DatabaseOptions } from './lib/database.js';
3
+ export interface ServerOptions {
4
+ database?: DatabaseOptions;
5
+ redis?: {
6
+ url: string;
7
+ };
8
+ cors?: {
9
+ origin: string | string[];
10
+ };
11
+ logger?: boolean;
12
+ }
13
+ export declare function createServer(options?: ServerOptions): Promise<FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>>;
14
+ export * from './lib/utils.js';
15
+ export * from './lib/database.js';
16
+ export * from './types/index.js';
17
+ export { redirectRoutes, linkRoutes, analyticsRoutes } from './routes/index.js';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAAsB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,kTA0B7D;AAGD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.analyticsRoutes = exports.linkRoutes = exports.redirectRoutes = void 0;
21
+ exports.createServer = createServer;
22
+ const fastify_1 = __importDefault(require("fastify"));
23
+ const cors_1 = __importDefault(require("@fastify/cors"));
24
+ const redis_1 = __importDefault(require("@fastify/redis"));
25
+ const database_js_1 = require("./lib/database.js");
26
+ const redirect_js_1 = require("./routes/redirect.js");
27
+ const links_js_1 = require("./routes/links.js");
28
+ const analytics_js_1 = require("./routes/analytics.js");
29
+ async function createServer(options = {}) {
30
+ const fastify = (0, fastify_1.default)({
31
+ logger: options.logger !== undefined ? options.logger : true,
32
+ });
33
+ // CORS
34
+ await fastify.register(cors_1.default, {
35
+ origin: options.cors?.origin || '*',
36
+ });
37
+ // Redis (optional)
38
+ if (options.redis?.url) {
39
+ await fastify.register(redis_1.default, {
40
+ url: options.redis.url,
41
+ });
42
+ }
43
+ // Database
44
+ await (0, database_js_1.initializeDatabase)(options.database);
45
+ // Routes
46
+ await fastify.register(redirect_js_1.redirectRoutes);
47
+ await fastify.register(links_js_1.linkRoutes);
48
+ await fastify.register(analytics_js_1.analyticsRoutes);
49
+ return fastify;
50
+ }
51
+ // Re-export utilities and types
52
+ __exportStar(require("./lib/utils.js"), exports);
53
+ __exportStar(require("./lib/database.js"), exports);
54
+ __exportStar(require("./types/index.js"), exports);
55
+ var index_js_1 = require("./routes/index.js");
56
+ Object.defineProperty(exports, "redirectRoutes", { enumerable: true, get: function () { return index_js_1.redirectRoutes; } });
57
+ Object.defineProperty(exports, "linkRoutes", { enumerable: true, get: function () { return index_js_1.linkRoutes; } });
58
+ Object.defineProperty(exports, "analyticsRoutes", { enumerable: true, get: function () { return index_js_1.analyticsRoutes; } });
59
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAmBA,oCA0BC;AA7CD,sDAAmD;AACnD,yDAAiC;AACjC,2DAAmC;AACnC,mDAAwE;AACxE,sDAAsD;AACtD,gDAA+C;AAC/C,wDAAwD;AAajD,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,OAAO,GAAG,IAAA,iBAAO,EAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC7D,CAAC,CAAC;IAEH,OAAO;IACP,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAI,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;KACpC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAK,EAAE;YAC5B,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;IACX,MAAM,IAAA,gCAAkB,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,4BAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,qBAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,8BAAe,CAAC,CAAC;IAExC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gCAAgC;AAChC,iDAA+B;AAC/B,oDAAkC;AAClC,mDAAiC;AACjC,8CAAgF;AAAvE,0GAAA,cAAc,OAAA;AAAE,sGAAA,UAAU,OAAA;AAAE,2GAAA,eAAe,OAAA"}
@@ -0,0 +1,11 @@
1
+ import pg from 'pg';
2
+ export interface DatabaseOptions {
3
+ url?: string;
4
+ pool?: {
5
+ min?: number;
6
+ max?: number;
7
+ };
8
+ }
9
+ export declare let db: pg.Pool;
10
+ export declare function initializeDatabase(options?: DatabaseOptions): Promise<void>;
11
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA6BvB,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBAoFrE"}