@potonz/shortlinks-manager-postgres 0.3.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/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @potonz/shortlinks-manager-postgres
2
+
3
+ PostgreSQL backend for short links manager using [postgres.js](https://github.com/porsager/postgres).
4
+
5
+ ## Features
6
+
7
+ - Full PostgreSQL support with prepared statements via postgres.js
8
+ - Automatic table creation and indexing
9
+ - Support for PostgreSQL 14, 15, 16, 17, and 18
10
+ - Type-safe SQL with tagged template literals
11
+ - Efficient parameterized queries
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ bun add @potonz/shortlinks-manager-postgres
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```typescript
22
+ import { createManager } from "@potonz/shortlinks-manager";
23
+ import { createPostgresBackend } from "@potonz/shortlinks-manager-postgres";
24
+
25
+ // Create backend with connection URI
26
+ const backend = createPostgresBackend("postgres://user:password@localhost:5432/shortlinks");
27
+
28
+ // Initialize tables (run once during setup)
29
+ await backend.setupTables();
30
+
31
+ // Create manager
32
+ const manager = await createManager({
33
+ backend,
34
+ shortIdLength: 6,
35
+ onShortIdLengthUpdated: (newLength) => {
36
+ console.log(`Short ID length updated to ${newLength}`);
37
+ },
38
+ });
39
+
40
+ // Create short link
41
+ const shortId = await manager.createShortLink("https://example.com");
42
+ console.log(`Created short link: ${shortId}`);
43
+
44
+ // Resolve short link
45
+ const targetUrl = await manager.getTargetUrl(shortId);
46
+ console.log(`Target URL: ${targetUrl}`);
47
+ ```
48
+
49
+ ## Database Schema
50
+
51
+ The backend automatically creates the following table:
52
+
53
+ ```sql
54
+ CREATE TABLE IF NOT EXISTS sl_links_map (
55
+ short_id VARCHAR(255) NOT NULL PRIMARY KEY,
56
+ target_url TEXT NOT NULL,
57
+ last_accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
58
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
59
+ );
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_sl_links_map_last_accessed_at
62
+ ON sl_links_map(last_accessed_at);
63
+ ```
64
+
65
+ ## API
66
+
67
+ ### `createPostgresBackend(connectionUri: string)`
68
+
69
+ Creates a PostgreSQL backend instance.
70
+
71
+ **Parameters:**
72
+ - `connectionUri` - PostgreSQL connection URI (e.g., `postgres://user:password@localhost:5432/dbname`)
73
+
74
+ **Returns:** `IShortLinksManagerPostgresBackend`
75
+
76
+ ### `backend.setupTables()`
77
+
78
+ Creates the required database tables and indexes. Should be called once during application initialization.
79
+
80
+ ### Backend Methods
81
+
82
+ Implements all `IShortLinksManagerBackend` methods:
83
+
84
+ - `getTargetUrl(shortId)` - Get target URL by short ID
85
+ - `createShortLink(shortId, targetUrl)` - Create a new short link
86
+ - `checkShortIdsExist(shortIds)` - Check which short IDs already exist
87
+ - `updateShortLinkLastAccessTime(shortId, time)` - Update last accessed timestamp
88
+ - `cleanUnusedLinks(maxAge)` - Remove links not accessed in `maxAge` days
89
+ - `removeShortLink(shortId)` - Remove a short link by ID
90
+
91
+ ## Testing
92
+
93
+ Tests run automatically in CI against PostgreSQL versions 14, 15, 16, 17, and 18.
94
+
95
+ To run tests locally:
96
+
97
+ ```bash
98
+ # Start PostgreSQL (using Docker)
99
+ docker run --name shortlinks-postgres -e POSTGRES_PASSWORD=password -e POSTGRES_DB=shortlinks -p 5432:5432 -d postgres:16
100
+
101
+ # Run tests
102
+ POSTGRES_URI=postgres://postgres:password@localhost:5432/shortlinks bun test packages/shortlinks-manager-postgres
103
+ ```
104
+
105
+ ## Supported PostgreSQL Versions
106
+
107
+ - PostgreSQL 14 (until 2026)
108
+ - PostgreSQL 15
109
+ - PostgreSQL 16
110
+ - PostgreSQL 17
111
+ - PostgreSQL 18 (latest)
112
+
113
+ ## License
114
+
115
+ MIT
@@ -0,0 +1,100 @@
1
+ // Generated by dts-bundle-generator v9.5.1
2
+
3
+ // Generated by dts-bundle-generator v9.5.1
4
+ export interface IBaseUrlRecord {
5
+ id: number;
6
+ baseUrl: string;
7
+ isActive?: boolean;
8
+ }
9
+ export interface IShortLinksManagerBackend {
10
+ /**
11
+ * Initialise any logic before the manager can do its thing. E.g. setting up tables.
12
+ * Run once when {@link createManager} is called
13
+ */
14
+ init?: () => unknown;
15
+ /**
16
+ * Get target URL for the given short ID
17
+ * @param {string} shortId
18
+ * @param {number} baseUrlId optional base URL ID to filter by
19
+ * @returns the target URL or null if not found
20
+ */
21
+ getTargetUrl(shortId: string, baseUrlId: number | null): string | null | Promise<string | null>;
22
+ /**
23
+ * Create a short link map with the given short ID and target URL
24
+ * @param {string} shortId
25
+ * @param {string} targetUrl
26
+ * @param {number} baseUrlId optional base URL ID
27
+ */
28
+ createShortLink(shortId: string, targetUrl: string, baseUrlId: number | null): void | Promise<void>;
29
+ /**
30
+ * Check the provided list of short IDs and return the ones that already exist.
31
+ * @param {string[]} shortIds
32
+ * @param {number} baseUrlId optional base URL ID to check within
33
+ */
34
+ checkShortIdsExist(shortIds: string[], baseUrlId: number | null): string[] | Promise<string[]>;
35
+ /**
36
+ * Update last accessed time to current timestamp
37
+ * @param shortId
38
+ * @param baseUrlId optional base URL ID to filter by
39
+ * @param time Unix timestamp or a Date object
40
+ */
41
+ updateShortLinkLastAccessTime(shortId: string, baseUrlId: number | null, time?: number | Date): void | Promise<void>;
42
+ /**
43
+ * Remove unused links that are older than the given maxAge
44
+ * @param maxAge number of days the record should be kept
45
+ * @returns an array of objects with shortId and baseUrlId that have been cleaned
46
+ */
47
+ cleanUnusedLinks(maxAge: number): Array<{
48
+ shortId: string;
49
+ baseUrlId: number | null;
50
+ }> | Promise<Array<{
51
+ shortId: string;
52
+ baseUrlId: number | null;
53
+ }>>;
54
+ /**
55
+ * Remove a short link by its ID
56
+ * @param shortId the short ID to remove
57
+ * @param baseUrlId optional base URL ID to filter by
58
+ */
59
+ removeShortLink(shortId: string, baseUrlId: number | null): void | Promise<void>;
60
+ baseUrl: {
61
+ /**
62
+ * Add a new base URL
63
+ * @param baseUrl the base URL to add
64
+ */
65
+ add(baseUrl: string): void | Promise<void>;
66
+ /**
67
+ * Remove a base URL by its ID
68
+ * @param id the ID of the base URL to remove
69
+ */
70
+ remove(id: number): void | Promise<void>;
71
+ /**
72
+ * List all base URLs
73
+ * @param includeInactive whether to include inactive base URLs (default: false)
74
+ * @returns array of base URL records
75
+ */
76
+ list(includeInactive?: boolean): IBaseUrlRecord[] | Promise<IBaseUrlRecord[]>;
77
+ /**
78
+ * Get the ID for a base URL
79
+ * @param baseUrl the base URL to get the ID for
80
+ * @returns the base URL ID or null if not found
81
+ */
82
+ getId(baseUrl: string): number | Promise<number>;
83
+ };
84
+ }
85
+ export interface IShortLinksManagerPostgresBackend extends IShortLinksManagerBackend {
86
+ setupTables: () => Promise<void>;
87
+ }
88
+ /**
89
+ * Create a PostgreSQL backend for short links manager using postgres.js
90
+ * @param connectionUri PostgreSQL connection URI (e.g., "postgres://user:pass@localhost/dbname")
91
+ * @returns IShortLinksManagerPostgresBackend implementation
92
+ */
93
+ export declare function createPostgresBackend(connectionUri: string): IShortLinksManagerPostgresBackend;
94
+ declare const _default: {};
95
+
96
+ export {
97
+ _default as default,
98
+ };
99
+
100
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,112 @@
1
+ /* MIT License
2
+
3
+ Copyright (c) 2025 Thomas Nguyen
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.
22
+ */
23
+ import Af from"os";import $f from"fs";var Ih=new Map,uu=new Map,nu=Symbol("OriginError"),Xh={};class lh extends Promise{constructor(h,n,f,l,w={}){let E,t;super((O,S)=>{E=O,t=S});this.tagged=Array.isArray(h.raw),this.strings=h,this.args=n,this.handler=f,this.canceller=l,this.options=w,this.state=null,this.statement=null,this.resolve=(O)=>(this.active=!1,E(O)),this.reject=(O)=>(this.active=!1,t(O)),this.active=!1,this.cancelled=null,this.executed=!1,this.signature="",this[nu]=this.handler.debug?Error():this.tagged&&mn(this.strings)}get origin(){return(this.handler.debug?this[nu].stack:this.tagged&&uu.has(this.strings)?uu.get(this.strings):uu.set(this.strings,this[nu].stack).get(this.strings))||""}static get[Symbol.species](){return Promise}cancel(){return this.canceller&&(this.canceller(this),this.canceller=null)}simple(){return this.options.simple=!0,this.options.prepare=!1,this}async readable(){return this.simple(),this.streaming=!0,this}async writable(){return this.simple(),this.streaming=!0,this}cursor(h=1,n){if(this.options.simple=!1,typeof h==="function")n=h,h=1;if(this.cursorRows=h,typeof n==="function")return this.cursorFn=n,this;let f;return{[Symbol.asyncIterator]:()=>({next:()=>{if(this.executed&&!this.active)return{done:!0};f&&f();let l=new Promise((w,E)=>{this.cursorFn=(t)=>{return w({value:t,done:!1}),new Promise((O)=>f=O)},this.resolve=()=>(this.active=!1,w({done:!0})),this.reject=(t)=>(this.active=!1,E(t))});return this.execute(),l},return(){return f&&f(Xh),{done:!0}}})}}describe(){return this.options.simple=!1,this.onlyDescribe=this.options.prepare=!0,this}stream(){throw Error(".stream has been renamed to .forEach")}forEach(h){return this.forEachFn=h,this.handle(),this}raw(){return this.isRaw=!0,this}values(){return this.isRaw="values",this}async handle(){!this.executed&&(this.executed=!0)&&await 1&&this.handler(this)}execute(){return this.handle(),this}then(){return this.handle(),super.then.apply(this,arguments)}catch(){return this.handle(),super.catch.apply(this,arguments)}finally(){return this.handle(),super.finally.apply(this,arguments)}}function mn(h){if(Ih.has(h))return Ih.get(h);let n=Error.stackTraceLimit;return Error.stackTraceLimit=4,Ih.set(h,Error()),Error.stackTraceLimit=n,Ih.get(h)}class Rh extends Error{constructor(h){super(h.message);this.name=this.constructor.name,Object.assign(this,h)}}var i={connection:Zu,postgres:Fu,generic:Hu,notSupported:zu};function Zu(h,n,f){let{host:l,port:w}=f||n,E=Object.assign(Error("write "+h+" "+(n.path||l+":"+w)),{code:h,errno:h,address:n.path||l},n.path?{}:{port:w});return Error.captureStackTrace(E,Zu),E}function Fu(h){let n=new Rh(h);return Error.captureStackTrace(n,Fu),n}function Hu(h,n){let f=Object.assign(Error(h+": "+n),{code:h});return Error.captureStackTrace(f,Hu),f}function zu(h){let n=Object.assign(Error(h+" (B) is not supported"),{code:"MESSAGE_NOT_SUPPORTED",name:h});return Error.captureStackTrace(n,zu),n}var bn={string:{to:25,from:null,serialize:(h)=>""+h},number:{to:0,from:[21,23,26,700,701],serialize:(h)=>""+h,parse:(h)=>+h},json:{to:114,from:[114,3802],serialize:(h)=>JSON.stringify(h),parse:(h)=>JSON.parse(h)},boolean:{to:16,from:16,serialize:(h)=>h===!0?"t":"f",parse:(h)=>h==="t"},date:{to:1184,from:[1082,1114,1184],serialize:(h)=>(h instanceof Date?h:new Date(h)).toISOString(),parse:(h)=>new Date(h)},bytea:{to:17,from:17,serialize:(h)=>"\\x"+Buffer.from(h).toString("hex"),parse:(h)=>Buffer.from(h.slice(2),"hex")}};class mh{then(){fu()}catch(){fu()}finally(){fu()}}class Vh extends mh{constructor(h){super();this.value=ah(h)}}class th extends mh{constructor(h,n,f){super();this.value=h,this.type=n,this.array=f}}class bh extends mh{constructor(h,n){super();this.first=h,this.rest=n}build(h,n,f,l){let w=kn.map(([E,t])=>({fn:t,i:h.search(E)})).sort((E,t)=>E.i-t.i).pop();return w.i===-1?Ou(this.first,l):w.fn(this.first,this.rest,n,f,l)}}function kh(h,n,f,l){let w=h instanceof th?h.value:h;if(w===void 0){if(h instanceof th?h.value=l.transform.undefined:w=h=l.transform.undefined,w===void 0)throw i.generic("UNDEFINED_VALUE","Undefined values are not allowed")}return"$"+f.push(h instanceof th?(n.push(h.value),h.array?h.array[h.type||dh(h.value)]||h.type||Vu(h.value):h.type):(n.push(h),dh(h)))}var Cu=Ku(bn);function wu(h,n,f,l,w,E){for(let t=1;t<h.strings.length;t++)n+=tu(n,f,l,w,E)+h.strings[t],f=h.args[t];return n}function tu(h,n,f,l,w){return n instanceof bh?n.build(h,f,l,w):n instanceof lh?cu(n,f,l,w):n instanceof Vh?n.value:n&&n[0]instanceof lh?n.reduce((E,t)=>E+" "+cu(t,f,l,w),""):kh(n,f,l,w)}function cu(h,n,f,l){return h.fragment=!0,wu(h,h.strings[0],h.args[0],n,f,l)}function Qu(h,n,f,l,w){return h.map((E)=>"("+l.map((t)=>tu("values",E[t],n,f,w)).join(",")+")").join(",")}function Ju(h,n,f,l,w){let E=Array.isArray(h[0]),t=n.length?n.flat():Object.keys(E?h[0]:h);return Qu(E?h:[h],f,l,t,w)}function ih(h,n,f,l,w){if(typeof h==="string"&&(h=[h].concat(n)),Array.isArray(h))return Ou(h,w);let E;return(n.length?n.flat():Object.keys(h)).map((O)=>{return E=h[O],(E instanceof lh?cu(E,f,l,w):E instanceof Vh?E.value:kh(E,f,l,w))+" as "+ah(w.transform.column.to?w.transform.column.to(O):O)}).join(",")}var kn=Object.entries({values:Ju,in:(...h)=>{let n=Ju(...h);return n==="()"?"(null)":n},select:ih,as:ih,returning:ih,"\\(":ih,update(h,n,f,l,w){return(n.length?n.flat():Object.keys(h)).map((E)=>ah(w.transform.column.to?w.transform.column.to(E):E)+"="+tu("values",h[E],f,l,w))},insert(h,n,f,l,w){let E=n.length?n.flat():Object.keys(Array.isArray(h)?h[0]:h);return"("+Ou(E,w)+")values"+Qu(Array.isArray(h)?h:[h],f,l,E,w)}}).map(([h,n])=>[new RegExp("((?:^|[\\s(])"+h+"(?:$|[\\s(]))(?![\\s\\S]*\\1)","i"),n]);function fu(){throw i.generic("NOT_TAGGED_CALL","Query not called as a tagged template literal")}var{serializers:an,parsers:en}=Cu;function Vu(h){if(Array.isArray(h))return Vu(h[0]);return typeof h==="string"?1009:0}var Wu=function(h){let n=Ku(h||{});return{serializers:Object.assign({},an,n.serializers),parsers:Object.assign({},en,n.parsers)}};function Ku(h){return Object.keys(h).reduce((n,f)=>{if(h[f].from&&[].concat(h[f].from).forEach((l)=>n.parsers[l]=h[f].parse),h[f].serialize)n.serializers[h[f].to]=h[f].serialize,h[f].from&&[].concat(h[f].from).forEach((l)=>n.serializers[l]=h[f].serialize);return n},{parsers:{},serializers:{}})}function Ou(h,{transform:{column:n}}){return h.map((f)=>ah(n.to?n.to(f):f)).join(",")}var ah=function(n){return'"'+n.replace(/"/g,'""').replace(/\./g,'"."')+'"'},dh=function h(n){return n instanceof th?n.type:n instanceof Date?1184:n instanceof Uint8Array?17:n===!0||n===!1?16:typeof n==="bigint"?20:Array.isArray(n)?h(n[0]):0},on=/\\/g,yn=/"/g;function pn(h){return h.replace(on,"\\\\").replace(yn,"\\\"")}var vu=function h(n,f,l,w){if(Array.isArray(n)===!1)return n;if(!n.length)return"{}";let E=n[0],t=w===1020?";":",";if(Array.isArray(E)&&!E.type)return"{"+n.map((O)=>h(O,f,l,w)).join(t)+"}";return"{"+n.map((O)=>{if(O===void 0){if(O=l.transform.undefined,O===void 0)throw i.generic("UNDEFINED_VALUE","Undefined values are not allowed")}return O===null?"null":'"'+pn(f?f(O.type?O.value:O):""+O)+'"'}).join(t)+"}"},lu={i:0,char:null,str:"",quoted:!1,last:0},Iu=function(n,f,l){return lu.i=lu.last=0,iu(lu,n,f,l)};function iu(h,n,f,l){let w=[],E=l===1020?";":",";for(;h.i<n.length;h.i++){if(h.char=n[h.i],h.quoted)if(h.char==="\\")h.str+=n[++h.i];else if(h.char==='"')w.push(f?f(h.str):h.str),h.str="",h.quoted=n[h.i+1]==='"',h.last=h.i+2;else h.str+=h.char;else if(h.char==='"')h.quoted=!0;else if(h.char==="{")h.last=++h.i,w.push(iu(h,n,f,l));else if(h.char==="}"){h.quoted=!1,h.last<h.i&&w.push(f?f(n.slice(h.last,h.i)):n.slice(h.last,h.i)),h.last=h.i+1;break}else if(h.char===E&&h.p!=="}"&&h.p!=='"')w.push(f?f(n.slice(h.last,h.i)):n.slice(h.last,h.i)),h.last=h.i+1;h.p=h.char}return h.last<h.i&&w.push(f?f(n.slice(h.last,h.i+1)):n.slice(h.last,h.i+1)),w}var jh=(h)=>{let n=h[0];for(let f=1;f<h.length;f++)n+=h[f]==="_"?h[++f].toUpperCase():h[f];return n},Mh=(h)=>{let n=h[0].toUpperCase();for(let f=1;f<h.length;f++)n+=h[f]==="_"?h[++f].toUpperCase():h[f];return n},Nh=(h)=>h.replace(/_/g,"-"),Jh=(h)=>h.replace(/([A-Z])/g,"_$1").toLowerCase(),Ch=(h)=>(h.slice(0,1)+h.slice(1).replace(/([A-Z])/g,"_$1")).toLowerCase(),Qh=(h)=>h.replace(/-/g,"_");function _u(h){return function n(f,l){return typeof f==="object"&&f!==null&&(l.type===114||l.type===3802)?Array.isArray(f)?f.map((w)=>n(w,l)):Object.entries(f).reduce((w,[E,t])=>Object.assign(w,{[h(E)]:n(t,l)}),{}):f}}jh.column={from:jh};jh.value={from:_u(jh)};Jh.column={to:Jh};var Eu={...jh};Eu.column.to=Jh;Mh.column={from:Mh};Mh.value={from:_u(Mh)};Ch.column={to:Ch};var Au={...Mh};Au.column.to=Ch;Nh.column={from:Nh};Nh.value={from:_u(Nh)};Qh.column={to:Qh};var $u={...Nh};$u.column.to=Qh;import du from"net";import xn from"tls";import Wh from"crypto";import Bu from"stream";import{performance as mu}from"perf_hooks";class Ph extends Array{constructor(){super();Object.defineProperties(this,{count:{value:null,writable:!0},state:{value:null,writable:!0},command:{value:null,writable:!0},columns:{value:null,writable:!0},statement:{value:null,writable:!0}})}static get[Symbol.species](){return Array}}var uh=qn;function qn(h=[]){let n=h.slice(),f=0;return{get length(){return n.length-f},remove:(l)=>{let w=n.indexOf(l);return w===-1?null:(n.splice(w,1),l)},push:(l)=>(n.push(l),l),shift:()=>{let l=n[f++];if(f===n.length)f=0,n=[];else n[f-1]=void 0;return l}}}var y=Buffer.allocUnsafe(256),rn="BCcDdEFfHPpQSX".split("").reduce((h,n)=>{let f=n.charCodeAt(0);return h[n]=()=>{return y[0]=f,U.i=5,U},h},{}),U=Object.assign(sn,rn,{N:String.fromCharCode(0),i:0,inc(h){return U.i+=h,U},str(h){let n=Buffer.byteLength(h);return eh(n),U.i+=y.write(h,U.i,n,"utf8"),U},i16(h){return eh(2),y.writeUInt16BE(h,U.i),U.i+=2,U},i32(h,n){if(n||n===0)return y.writeUInt32BE(h,n),U;return eh(4),y.writeUInt32BE(h,U.i),U.i+=4,U},z(h){return eh(h),y.fill(0,U.i,U.i+h),U.i+=h,U},raw(h){return y=Buffer.concat([y.subarray(0,U.i),h]),U.i=y.length,U},end(h=1){y.writeUInt32BE(U.i-h,h);let n=y.subarray(0,U.i);return U.i=0,y=Buffer.allocUnsafe(256),n}}),B=U;function eh(h){if(y.length-U.i<h){let n=y,f=n.length;y=Buffer.allocUnsafe(f+(f>>1)+h),n.copy(y)}}function sn(){return U.i=0,U}var Su=au,hf=1,Sh=B().S().end(),bu=B().H().end(),uf=B().i32(8).i32(80877103).end(8),nf=Buffer.concat([B().E().str(B.N).i32(0).end(),Sh]),ff=B().D().str("S").str(B.N).end(),Uh=()=>{},lf=new Set(["FetchPreparedStatement","RevalidateCachedQuery","transformAssignedExpr"]),cf={83:"severity_local",86:"severity",67:"code",77:"message",68:"detail",72:"hint",80:"position",112:"internal_position",113:"internal_query",87:"where",115:"schema_name",116:"table_name",99:"column_name",100:"data type_name",110:"constraint_name",70:"file",76:"line",82:"routine"};function au(h,n={},{onopen:f=Uh,onend:l=Uh,onclose:w=Uh}={}){let{sslnegotiation:E,ssl:t,max:O,user:S,host:K,port:Z,database:R,parsers:N,transform:P,onnotice:C,onnotify:g,onparameter:b,max_pipeline:z,keep_alive:ch,backoff:nh,target_session_attrs:x}=h,D=uh(),$h=hf++,Oh={pid:null,secret:null},Lh=Gu(xh,h.idle_timeout),gh=Gu(xh,h.max_lifetime),Y=Gu(hn,h.connect_timeout),$=null,_h,s=null,T=new Ph,p=Buffer.alloc(0),Dh=h.fetch_types,Eh={},_={},j=Math.random().toString(36).slice(2),J=1,d=0,v=0,M=0,X=0,V=0,W=0,m=0,q=null,F=null,Ah=!1,wh=null,Bh=null,a=null,Q=null,H=null,hh=null,Kh=null,rh=null,A=null,Zh=null,e={queue:n.closed,idleTimer:Lh,connect(u){a=u,Yu()},terminate:zh,execute:Fh,cancel:qu,end:xh,count:0,id:$h};return n.closed&&n.closed.push(e),e;async function pu(){let u;try{u=h.socket?await Promise.resolve(h.socket(h)):new du.Socket}catch(c){Th(c);return}return u.on("error",Th),u.on("close",Tu),u.on("drain",Lu),u}async function qu({pid:u,secret:c},G,L){try{_h=B().i32(16).i32(80877102).i32(u).i32(c).end(16),await Du(),$.once("error",L),$.once("close",G)}catch(I){L(I)}}function Fh(u){if(Ah)return Hh(u,i.connection("CONNECTION_DESTROYED",h));if(H)return Hh(u,i.generic("COPY_IN_PROGRESS","You cannot execute queries during copy"));if(u.cancelled)return;try{return u.state=Oh,A?D.push(u):(A=u,A.active=!0),xu(u),k(ru(u))&&!u.describeFirst&&!u.cursorFn&&D.length<z&&(!u.options.onexecute||u.options.onexecute(e))}catch(c){return D.length===0&&k(Sh),fh(c),!0}}function ru(u){if(u.parameters.length>=65534)throw i.generic("MAX_PARAMETERS_EXCEEDED","Max number of parameters (65534) exceeded");return u.options.simple?B().Q().str(u.statement.string+B.N).end():u.describeFirst?Buffer.concat([Mu(u),bu]):u.prepare?u.prepared?vh(u):Buffer.concat([Mu(u),vh(u)]):su(u)}function Mu(u){return Buffer.concat([Ru(u.statement.string,u.parameters,u.statement.types,u.statement.name),vn("S",u.statement.name)])}function vh(u){return Buffer.concat([Kn(u.parameters,u.statement.types,u.statement.name,u.cursorName),u.cursorFn?Uu("",u.cursorRows):nf])}function su(u){return Buffer.concat([Ru(u.statement.string,u.parameters,u.statement.types),ff,vh(u)])}function xu(u){let c=[],G=[],L=wu(u,u.strings[0],u.args[0],c,G,h);!u.tagged&&u.args.forEach((I)=>kh(I,c,G,h)),u.prepare=h.prepare&&("prepare"in u.options?u.options.prepare:!0),u.string=L,u.signature=u.prepare&&G+L,u.onlyDescribe&&delete _[u.signature],u.parameters=u.parameters||c,u.prepared=u.prepare&&u.signature in _,u.describeFirst=u.onlyDescribe||c.length&&!u.prepared,u.statement=u.prepared?_[u.signature]:{string:L,types:G,name:u.prepare?j+J++:""},typeof h.debug==="function"&&h.debug($h,L,c,G)}function k(u,c){if(hh=hh?Buffer.concat([hh,u]):Buffer.from(u),c||hh.length>=1024)return Nu(c);return F===null&&(F=setImmediate(Nu)),!0}function Nu(u){let c=$.write(hh,u);return F!==null&&clearImmediate(F),hh=F=null,c}function hn(){fh(i.connection("CONNECT_TIMEOUT",h,$)),$.destroy()}async function Pu(){if(E!=="direct"){if(k(uf),!await new Promise((G)=>$.once("data",(L)=>G(L[0]===83)))&&t==="prefer")return Yh()}let u={socket:$,servername:du.isIP($.host)?void 0:$.host};if(E==="direct")u.ALPNProtocols=["postgresql"];if(t==="require"||t==="allow"||t==="prefer")u.rejectUnauthorized=!1;else if(typeof t==="object")Object.assign(u,t);$.removeAllListeners(),$=xn.connect(u),$.on("secureConnect",Yh),$.on("error",Th),$.on("close",Tu),$.on("drain",Lu)}function Lu(){!A&&f(e)}function sh(u){if(wh){if(wh.push(u),v-=u.length,v>0)return}p=wh?Buffer.concat(wh,V-v):p.length===0?u:Buffer.concat([p,u],p.length+u.length);while(p.length>4){if(V=p.readUInt32BE(1),V>=p.length){v=V-p.length,wh=[p];break}try{un(p.subarray(0,V+1))}catch(c){A&&(A.cursorFn||A.describeFirst)&&k(Sh),fh(c)}p=p.subarray(V+1),v=0,wh=null}}async function Du(){if(Ah=!1,Eh={},$||($=await pu()),!$)return;if(Y.start(),h.socket)return t?Pu():Yh();if($.on("connect",t?Pu:Yh),h.path)return $.connect(h.path);$.ssl=t,$.connect(Z[M],K[M]),$.host=K[M],$.port=Z[M],M=(M+1)%Z.length}function Yu(){setTimeout(Du,d?Math.max(0,d+W-mu.now()):0)}function Yh(){try{_={},Dh=h.fetch_types,j=Math.random().toString(36).slice(2),J=1,gh.start(),$.on("data",sh),ch&&$.setKeepAlive&&$.setKeepAlive(!0,1000*ch);let u=dn();k(u)}catch(u){Th(u)}}function Th(u){if(e.queue===n.connecting&&h.host[X+1])return;fh(u);while(D.length)Hh(D.shift(),u)}function fh(u){H&&(H.destroy(u),H=null),A&&Hh(A,u),a&&(Hh(a,u),a=null)}function Hh(u,c){if(u.reserve)return u.reject(c);if(!c||typeof c!=="object")c=Error(c);"query"in c||"parameters"in c||Object.defineProperties(c,{stack:{value:c.stack+u.origin.replace(/.*\n/,`
24
+ `),enumerable:h.debug},query:{value:u.string,enumerable:h.debug},parameters:{value:u.parameters,enumerable:h.debug},args:{value:u.args,enumerable:h.debug},types:{value:u.statement&&u.statement.types,enumerable:h.debug}}),u.reject(c)}function xh(){return Q||(!e.reserved&&l(e),!e.reserved&&!a&&!A&&D.length===0?(zh(),new Promise((u)=>$&&$.readyState!=="closed"?$.once("close",u):u())):Q=new Promise((u)=>Kh=u))}function zh(){if(Ah=!0,H||A||a||D.length)Th(i.connection("CONNECTION_DESTROYED",h));if(clearImmediate(F),$)$.removeListener("data",sh),$.removeListener("connect",Yh),$.readyState==="open"&&$.end(B().X().end());Kh&&(Kh(),Q=Kh=null)}async function Tu(u){if(p=Buffer.alloc(0),v=0,wh=null,clearImmediate(F),$.removeListener("data",sh),$.removeListener("connect",Yh),Lh.cancel(),gh.cancel(),Y.cancel(),$.removeAllListeners(),$=null,a)return Yu();!u&&(A||D.length)&&Th(i.connection("CONNECTION_CLOSED",h,$)),d=mu.now(),u&&h.shared.retries++,W=(typeof nh==="function"?nh(h.shared.retries):nh)*1000,w(e,i.connection("CONNECTION_CLOSED",h,$))}function un(u,c=u[0]){(c===68?nn:c===100?Fn:c===65?Yn:c===83?fn:c===90?ln:c===67?cn:c===50?Xu:c===49?wn:c===116?tn:c===84?On:c===82?_n:c===110?Sn:c===75?gn:c===69?Ln:c===115?Tn:c===51?Xn:c===71?Rn:c===78?zn:c===72?Un:c===99?Hn:c===73?Jn:c===86?Cn:c===118?Qn:c===87?Zn:Vn)(u)}function nn(u){let c=7,G,L,I,o=A.isRaw?Array(A.statement.columns.length):{};for(let r=0;r<A.statement.columns.length;r++)L=A.statement.columns[r],G=u.readInt32BE(c),c+=4,I=G===-1?null:A.isRaw===!0?u.subarray(c,c+=G):L.parser===void 0?u.toString("utf8",c,c+=G):L.parser.array===!0?L.parser(u.toString("utf8",c+1,c+=G)):L.parser(u.toString("utf8",c,c+=G)),A.isRaw?o[r]=A.isRaw===!0?I:P.value.from?P.value.from(I,L):I:o[L.name]=P.value.from?P.value.from(I,L):I;A.forEachFn?A.forEachFn(P.row.from?P.row.from(o):o,T):T[m++]=P.row.from?P.row.from(o):o}function fn(u){let[c,G]=u.toString("utf8",5,u.length-1).split(B.N);if(Eh[c]=G,h.parameters[c]!==G)h.parameters[c]=G,b&&b(c,G)}function ln(u){if(A)if(s)A.retried?fh(A.retried):A.prepared&&lf.has(s.routine)?Dn(A,s):fh(s);else A.resolve(Bh||T);else if(s)fh(s);if(A=Bh=s=null,T=new Ph,Y.cancel(),a){if(x){if(!Eh.in_hot_standby||!Eh.default_transaction_read_only)return Pn();else if(Nn(x,Eh))return zh()}if(Dh)return a.reserve&&(a=null),jn();a&&!a.reserve&&Fh(a),h.shared.retries=X=0,a=null;return}while(D.length&&(A=D.shift())&&(A.active=!0,A.cancelled))au(h).cancel(A.state,A.cancelled.resolve,A.cancelled.reject);if(A)return;e.reserved?!e.reserved.release&&u[5]===73?Q?zh():(e.reserved=null,f(e)):e.reserved():Q?zh():f(e)}function cn(u){m=0;for(let c=u.length-1;c>0;c--){if(u[c]===32&&u[c+1]<58&&T.count===null)T.count=+u.toString("utf8",c+1,u.length-1);if(u[c-1]>=65){T.command=u.toString("utf8",5,c),T.state=Oh;break}}if(Zh&&(Zh(),Zh=null),T.command==="BEGIN"&&O!==1&&!e.reserved)return fh(i.generic("UNSAFE_TRANSACTION","Only use sql.begin, sql.reserved or max: 1"));if(A.options.simple)return Xu();if(A.cursorFn)T.count&&A.cursorFn(T),k(Sh)}function wn(){A.parsing=!1}function Xu(){!T.statement&&(T.statement=A.statement),T.columns=A.statement.columns}function tn(u){let c=u.readUInt16BE(5);for(let G=0;G<c;++G)!A.statement.types[G]&&(A.statement.types[G]=u.readUInt32BE(7+G*4));A.prepare&&(_[A.signature]=A.statement),A.describeFirst&&!A.onlyDescribe&&(k(vh(A)),A.describeFirst=!1)}function On(u){if(T.command)Bh=Bh||[T],Bh.push(T=new Ph),T.count=null,A.statement.columns=null;let c=u.readUInt16BE(5),G=7,L;A.statement.columns=Array(c);for(let I=0;I<c;++I){L=G;while(u[G++]!==0);let o=u.readUInt32BE(G),r=u.readUInt16BE(G+4),Gh=u.readUInt32BE(G+6);A.statement.columns[I]={name:P.column.from?P.column.from(u.toString("utf8",L,G-1)):u.toString("utf8",L,G-1),parser:N[Gh],table:o,number:r,type:Gh},G+=18}if(T.statement=A.statement,A.onlyDescribe)return A.resolve(A.statement),k(Sh)}async function _n(u,c=u.readUInt32BE(5)){(c===3?En:c===5?An:c===10?$n:c===11?Bn:c===12?Gn:c!==0?Wn:Uh)(u,c)}async function En(){let u=await hu();k(B().p().str(u).z(1).end())}async function An(u){let c="md5"+await ku(Buffer.concat([Buffer.from(await ku(await hu()+S)),u.subarray(9)]));k(B().p().str(c).z(1).end())}async function $n(){rh=(await Wh.randomBytes(18)).toString("base64"),B().p().str("SCRAM-SHA-256"+B.N);let u=B.i;k(B.inc(4).str("n,,n=*,r="+rh).i32(B.i-u-4,u).end())}async function Bn(u){let c=u.toString("utf8",9).split(",").reduce((r,Gh)=>(r[Gh[0]]=Gh.slice(2),r),{}),G=await Wh.pbkdf2Sync(await hu(),Buffer.from(c.s,"base64"),parseInt(c.i),32,"sha256"),L=await yh(G,"Client Key"),I="n=*,r="+rh+",r="+c.r+",s="+c.s+",i="+c.i+",c=biws,r="+c.r;q=(await yh(await yh(G,"Server Key"),I)).toString("base64");let o="c=biws,r="+c.r+",p="+tf(L,Buffer.from(await yh(await wf(L),I))).toString("base64");k(B().p().str(o).end())}function Gn(u){if(u.toString("utf8",9).split(B.N,1)[0].slice(2)===q)return;fh(i.generic("SASL_SIGNATURE_MISMATCH","The server did not return the correct signature")),$.destroy()}function hu(){return Promise.resolve(typeof h.pass==="function"?h.pass():h.pass)}function Sn(){if(T.statement=A.statement,T.statement.columns=[],A.onlyDescribe)return A.resolve(A.statement),k(Sh)}function gn(u){Oh.pid=u.readUInt32BE(5),Oh.secret=u.readUInt32BE(9)}async function jn(){Dh=!1,(await new lh([`
25
+ select b.oid, b.typarray
26
+ from pg_catalog.pg_type a
27
+ left join pg_catalog.pg_type b on b.oid = a.typelem
28
+ where a.typcategory = 'A'
29
+ group by b.oid, b.typarray
30
+ order by b.oid
31
+ `],[],Fh)).forEach(({oid:c,typarray:G})=>Mn(c,G))}function Mn(u,c){if(!!h.parsers[c]&&!!h.serializers[c])return;let G=h.parsers[u];h.shared.typeArrayMap[u]=c,h.parsers[c]=(L)=>Iu(L,G,c),h.parsers[c].array=!0,h.serializers[c]=(L)=>vu(L,h.serializers[u],h,c)}function Nn(u,c){return u==="read-write"&&c.default_transaction_read_only==="on"||u==="read-only"&&c.default_transaction_read_only==="off"||u==="primary"&&c.in_hot_standby==="on"||u==="standby"&&c.in_hot_standby==="off"||u==="prefer-standby"&&c.in_hot_standby==="off"&&h.host[X]}function Pn(){let u=new lh([`
32
+ show transaction_read_only;
33
+ select pg_catalog.pg_is_in_recovery()
34
+ `],[],Fh,null,{simple:!0});u.resolve=([[c],[G]])=>{Eh.default_transaction_read_only=c.transaction_read_only,Eh.in_hot_standby=G.pg_is_in_recovery?"on":"off"},u.execute()}function Ln(u){if(A)(A.cursorFn||A.describeFirst)&&k(Sh),s=i.postgres(oh(u));else fh(i.postgres(oh(u)))}function Dn(u,c){delete _[u.signature],u.retried=c,Fh(u)}function Yn(u){if(!g)return;let c=9;while(u[c++]!==0);g(u.toString("utf8",9,c-1),u.toString("utf8",c,u.length-1))}async function Tn(){try{let u=await Promise.resolve(A.cursorFn(T));m=0,u===Xh?k(In(A.portal)):(T=new Ph,k(Uu("",A.cursorRows)))}catch(u){k(Sh),A.reject(u)}}function Xn(){T.count&&A.cursorFn(T),A.resolve(T)}function Rn(){H=new Bu.Writable({autoDestroy:!0,write(u,c,G){$.write(B().d().raw(u).end(),G)},destroy(u,c){c(u),$.write(B().f().str(u+B.N).end()),H=null},final(u){$.write(B().c().end()),Zh=u,H=null}}),A.resolve(H)}function Un(){H=new Bu.Readable({read(){$.resume()}}),A.resolve(H)}function Zn(){H=new Bu.Duplex({autoDestroy:!0,read(){$.resume()},write(u,c,G){$.write(B().d().raw(u).end(),G)},destroy(u,c){c(u),$.write(B().f().str(u+B.N).end()),H=null},final(u){$.write(B().c().end()),Zh=u}}),A.resolve(H)}function Fn(u){H&&(H.push(u.subarray(5))||$.pause())}function Hn(){H&&H.push(null),H=null}function zn(u){C?C(oh(u)):console.log(oh(u))}function Jn(){}function Cn(){fh(i.notSupported("FunctionCallResponse"))}function Qn(){fh(i.notSupported("NegotiateProtocolVersion"))}function Vn(u){console.error("Postgres.js : Unknown Message:",u[0])}function Wn(u,c){console.error("Postgres.js : Unknown Auth:",c)}function Kn(u,c,G="",L=""){let I,o;return B().B().str(L+B.N).str(G+B.N).i16(0).i16(u.length),u.forEach((r,Gh)=>{if(r===null)return B.i32(4294967295);o=c[Gh],u[Gh]=r=o in h.serializers?h.serializers[o](r):""+r,I=B.i,B.inc(4).str(r).i32(B.i-I-4,I)}),B.i16(0),B.end()}function Ru(u,c,G,L=""){return B().P().str(L+B.N).str(u+B.N).i16(c.length),c.forEach((I,o)=>B.i32(G[o]||0)),B.end()}function vn(u,c=""){return B().D().str(u).str(c+B.N).end()}function Uu(u="",c=0){return Buffer.concat([B().E().str(u+B.N).i32(c).end(),bu])}function In(u=""){return Buffer.concat([B().C().str("P").str(u+B.N).end(),B().S().end()])}function dn(){return _h||B().inc(4).i16(3).z(2).str(Object.entries(Object.assign({user:S,database:R,client_encoding:"UTF8"},h.connection)).filter(([,u])=>u).map(([u,c])=>u+B.N+c).join(B.N)).z(2).end(0)}}function oh(h){let n={},f=5;for(let l=5;l<h.length-1;l++)if(h[l]===0)n[cf[h[f]]]=h.toString("utf8",f+1,l),f=l+1;return n}function ku(h){return Wh.createHash("md5").update(h).digest("hex")}function yh(h,n){return Wh.createHmac("sha256",h).update(n).digest()}function wf(h){return Wh.createHash("sha256").update(h).digest()}function tf(h,n){let f=Math.max(h.length,n.length),l=Buffer.allocUnsafe(f);for(let w=0;w<f;w++)l[w]=h[w]^n[w];return l}function Gu(h,n){if(n=typeof n==="function"?n():n,!n)return{cancel:Uh,start:Uh};let f;return{cancel(){f&&(clearTimeout(f),f=null)},start(){f&&clearTimeout(f),f=setTimeout(l,n*1000,arguments)}};function l(w){h.apply(null,w),f=null}}var eu=()=>{};function gu(h,n){let f=new Map,l="postgresjs_"+Math.random().toString(36).slice(2),w={},E,t,O=!1,S=R.sql=h({...n,transform:{column:{},value:{},row:{}},max:1,fetch_types:!1,idle_timeout:null,max_lifetime:null,connection:{...n.connection,replication:"database"},onclose:async function(){if(O)return;t=null,w.pid=w.secret=void 0,N(await P(S,l,n.publications)),f.forEach((g)=>g.forEach(({onsubscribe:b})=>b()))},no_subscribe:!0}),K=S.end,Z=S.close;return S.end=async()=>{return O=!0,t&&await new Promise((g)=>(t.once("close",g),t.end())),K()},S.close=async()=>{return t&&await new Promise((g)=>(t.once("close",g),t.end())),Z()},R;async function R(g,b,z=eu,ch=eu){if(g=Ef(g),!E)E=P(S,l,n.publications);let nh={fn:b,onsubscribe:z},x=f.has(g)?f.get(g).add(nh):f.set(g,new Set([nh])).get(g),D=()=>{x.delete(nh),x.size===0&&f.delete(g)};return E.then(($h)=>{return N($h),z(),t&&t.on("error",ch),{unsubscribe:D,state:w,sql:S}})}function N(g){t=g.stream,w.pid=g.state.pid,w.secret=g.state.secret}async function P(g,b,z){if(!z)throw Error("Missing publication names");let ch=await g.unsafe(`CREATE_REPLICATION_SLOT ${b} TEMPORARY LOGICAL pgoutput NOEXPORT_SNAPSHOT`),[nh]=ch,x=await g.unsafe(`START_REPLICATION SLOT ${b} LOGICAL ${nh.consistent_point} (proto_version '1', publication_names '${z}')`).writable(),D={lsn:Buffer.concat(nh.consistent_point.split("/").map((Y)=>Buffer.from(("00000000"+Y).slice(-8),"hex")))};return x.on("data",Oh),x.on("error",$h),x.on("close",g.close),{stream:x,state:ch.state};function $h(Y){console.error("Unexpected error during logical streaming - reconnecting",Y)}function Oh(Y){if(Y[0]===119)_f(Y.subarray(25),D,g.options.parsers,Lh,n.transform);else if(Y[0]===107&&Y[17])D.lsn=Y.subarray(1,9),gh()}function Lh(Y,$){let _h=$.relation.schema+"."+$.relation.table;C("*",Y,$),C("*:"+_h,Y,$),$.relation.keys.length&&C("*:"+_h+"="+$.relation.keys.map((s)=>Y[s.name]),Y,$),C($.command,Y,$),C($.command+":"+_h,Y,$),$.relation.keys.length&&C($.command+":"+_h+"="+$.relation.keys.map((s)=>Y[s.name]),Y,$)}function gh(){let Y=Buffer.alloc(34);Y[0]=114,Y.fill(D.lsn,1),Y.writeBigInt64BE(BigInt(Date.now()-Date.UTC(2000,0,1))*BigInt(1000),25),x.write(Y)}}function C(g,b,z){f.has(g)&&f.get(g).forEach(({fn:ch})=>ch(b,z,g))}}function Of(h){return new Date(Date.UTC(2000,0,1)+Number(h/BigInt(1000)))}function _f(h,n,f,l,w){let E=(t,[O,S])=>(t[O.charCodeAt(0)]=S,t);Object.entries({R:(t)=>{let O=1,S=n[t.readUInt32BE(O)]={schema:t.toString("utf8",O+=4,O=t.indexOf(0,O))||"pg_catalog",table:t.toString("utf8",O+1,O=t.indexOf(0,O+1)),columns:Array(t.readUInt16BE(O+=2)),keys:[]};O+=2;let K=0,Z;while(O<t.length)Z=S.columns[K++]={key:t[O++],name:w.column.from?w.column.from(t.toString("utf8",O,O=t.indexOf(0,O))):t.toString("utf8",O,O=t.indexOf(0,O)),type:t.readUInt32BE(O+=1),parser:f[t.readUInt32BE(O)],atttypmod:t.readUInt32BE(O+=4)},Z.key&&S.keys.push(Z),O+=4},Y:()=>{},O:()=>{},B:(t)=>{n.date=Of(t.readBigInt64BE(9)),n.lsn=t.subarray(1,9)},I:(t)=>{let O=1,S=n[t.readUInt32BE(O)],{row:K}=ph(t,S.columns,O+=7,w);l(K,{command:"insert",relation:S})},D:(t)=>{let O=1,S=n[t.readUInt32BE(O)];O+=4;let K=t[O]===75;l(K||t[O]===79?ph(t,S.columns,O+=3,w).row:null,{command:"delete",relation:S,key:K})},U:(t)=>{let O=1,S=n[t.readUInt32BE(O)];O+=4;let K=t[O]===75,Z=K||t[O]===79?ph(t,S.columns,O+=3,w):null;Z&&(O=Z.i);let{row:R}=ph(t,S.columns,O+3,w);l(R,{command:"update",relation:S,key:K,old:Z&&Z.row})},T:()=>{},C:()=>{}}).reduce(E,{})[h[0]](h)}function ph(h,n,f,l){let w,E,t,O=l.raw?Array(n.length):{};for(let S=0;S<n.length;S++)w=h[f++],E=n[S],t=w===110?null:w===117?void 0:E.parser===void 0?h.toString("utf8",f+4,f+=4+h.readUInt32BE(f)):E.parser.array===!0?E.parser(h.toString("utf8",f+5,f+=4+h.readUInt32BE(f))):E.parser(h.toString("utf8",f+4,f+=4+h.readUInt32BE(f))),l.raw?O[S]=l.raw===!0?t:l.value.from?l.value.from(t,E):t:O[E.name]=l.value.from?l.value.from(t,E):t;return{i:f,row:l.row.from?l.row.from(O):O}}function Ef(h){let n=h.match(/^(\*|insert|update|delete)?:?([^.]+?\.?[^=]+)?=?(.+)?/i)||[];if(!n)throw Error("Malformed subscribe pattern: "+h);let[,f,l,w]=n;return(f||"*")+(l?":"+(l.indexOf(".")===-1?"public."+l:l):"")+(w?"="+w:"")}import ou from"stream";function ju(h,n,f=393216){return new Promise(async(l,w)=>{await h.begin(async(E)=>{let t;!n&&([{oid:n}]=await E`select lo_creat(-1) as oid`);let[{fd:O}]=await E`select lo_open(${n}, ${f}) as fd`,S={writable:Z,readable:K,close:()=>E`select lo_close(${O})`.then(t),tell:()=>E`select lo_tell64(${O})`,read:(R)=>E`select loread(${O}, ${R}) as data`,write:(R)=>E`select lowrite(${O}, ${R})`,truncate:(R)=>E`select lo_truncate64(${O}, ${R})`,seek:(R,N=0)=>E`select lo_lseek64(${O}, ${R}, ${N})`,size:()=>E`
35
+ select
36
+ lo_lseek64(${O}, location, 0) as position,
37
+ seek.size
38
+ from (
39
+ select
40
+ lo_lseek64($1, 0, 2) as size,
41
+ tell.location
42
+ from (select lo_tell64($1) as location) tell
43
+ ) seek
44
+ `};return l(S),new Promise(async(R)=>t=R);async function K({highWaterMark:R=16384,start:N=0,end:P=1/0}={}){let C=P-N;return N&&await S.seek(N),new ou.Readable({highWaterMark:R,async read(g){let b=g>C?g-C:g;C-=g;let[{data:z}]=await S.read(b);if(this.push(z),z.length<g)this.push(null)}})}async function Z({highWaterMark:R=16384,start:N=0}={}){return N&&await S.seek(N),new ou.Writable({highWaterMark:R,write(P,C,g){S.write(P).then(()=>g(),g)}})}}).catch(w)})}Object.assign(qh,{PostgresError:Rh,toPascal:Mh,pascal:Au,toCamel:jh,camel:Eu,toKebab:Nh,kebab:$u,fromPascal:Ch,fromCamel:Jh,fromKebab:Qh,BigInt:{to:20,from:[20],parse:(h)=>BigInt(h),serialize:(h)=>h.toString()}});var yu=qh;function qh(h,n){let f=Bf(h,n),l=f.no_subscribe||gu(qh,{...f}),w=!1,E=uh(),t=uh(),O=uh(),S=uh(),K=uh(),Z=uh(),R=uh(),N=uh(),P={connecting:t,reserved:O,closed:S,ended:K,open:Z,busy:R,full:N},C=[...Array(f.max)].map(()=>Su(f,P,{onopen:Dh,onend:p,onclose:Eh})),g=b(Lh);return Object.assign(g,{get parameters(){return f.parameters},largeObject:ju.bind(null,g),subscribe:l,CLOSE:Xh,END:Xh,PostgresError:Rh,options:f,reserve:nh,listen:z,begin:x,close:_h,end:$}),g;function b(_){return _.debug=f.debug,Object.entries(f.types).reduce((M,[X,V])=>{return M[X]=(W)=>new th(W,V.to),M},j),Object.assign(J,{types:j,typed:j,unsafe:d,notify:ch,array:Oh,json:$h,file:v}),J;function j(M,X){return new th(M,X)}function J(M,...X){return M&&Array.isArray(M.raw)?new lh(M,X,_,Y):typeof M==="string"&&!X.length?new Vh(f.transform.column.to?f.transform.column.to(M):M):new bh(M,X)}function d(M,X=[],V={}){return arguments.length===2&&!Array.isArray(X)&&(V=X,X=[]),new lh([M],X,_,Y,{prepare:!1,...V,simple:"simple"in V?V.simple:X.length===0})}function v(M,X=[],V={}){return arguments.length===2&&!Array.isArray(X)&&(V=X,X=[]),new lh([],X,(m)=>{$f.readFile(M,"utf8",(q,F)=>{if(q)return m.reject(q);m.strings=[F],_(m)})},Y,{...V,simple:"simple"in V?V.simple:X.length===0})}}async function z(_,j,J){let d={fn:j,onlisten:J},v=z.sql||(z.sql=qh({...f,max:1,idle_timeout:null,max_lifetime:null,fetch_types:!1,onclose(){Object.entries(z.channels).forEach(([m,{listeners:q}])=>{delete z.channels[m],Promise.all(q.map((F)=>z(m,F.fn,F.onlisten).catch(()=>{})))})},onnotify(m,q){m in z.channels&&z.channels[m].listeners.forEach((F)=>F.fn(q))}})),M=z.channels||(z.channels={});if(_ in M){M[_].listeners.push(d);let m=await M[_].result;return d.onlisten&&d.onlisten(),{state:m.state,unlisten:W}}M[_]={result:v`listen ${v.unsafe('"'+_.replace(/"/g,'""')+'"')}`,listeners:[d]};let V=await M[_].result;return d.onlisten&&d.onlisten(),{state:V.state,unlisten:W};async function W(){if(_ in M===!1)return;if(M[_].listeners=M[_].listeners.filter((m)=>m!==d),M[_].listeners.length)return;return delete M[_],v`unlisten ${v.unsafe('"'+_.replace(/"/g,'""')+'"')}`}}async function ch(_,j){return await g`select pg_notify(${_}, ${""+j})`}async function nh(){let _=uh(),j=Z.length?Z.shift():await new Promise((v,M)=>{let X={reserve:v,reject:M};E.push(X),S.length&&T(S.shift(),X)});D(j,O),j.reserved=()=>_.length?j.execute(_.shift()):D(j,O),j.reserved.release=!0;let J=b(d);return J.release=()=>{j.reserved=null,Dh(j)},J;function d(v){j.queue===N?_.push(v):j.execute(v)||D(j,N)}}async function x(_,j){!j&&(j=_,_="");let J=uh(),d=0,v,M=null;try{return await g.unsafe("begin "+_.replace(/[^a-z ]/ig,""),[],{onexecute:V}).execute(),await Promise.race([X(v,j),new Promise((W,m)=>v.onclose=m)])}catch(W){throw W}async function X(W,m,q){let F=b(a);F.savepoint=Bh,F.prepare=(Q)=>M=Q.replace(/[^a-z0-9$-_. ]/gi);let Ah,wh;q&&await F`savepoint ${F(q)}`;try{if(wh=await new Promise((Q,H)=>{let hh=m(F);Promise.resolve(Array.isArray(hh)?Promise.all(hh):hh).then(Q,H)}),Ah)throw Ah}catch(Q){throw await(q?F`rollback to ${F(q)}`:F`rollback`),Q instanceof Rh&&Q.code==="25P02"&&Ah||Q}if(!q)M?await F`prepare transaction '${F.unsafe(M)}'`:await F`commit`;return wh;function Bh(Q,H){if(Q&&Array.isArray(Q.raw))return Bh((hh)=>hh.apply(hh,arguments));return arguments.length===1&&(H=Q,Q=null),X(W,H,"s"+d+++(Q?"_"+Q:""))}function a(Q){Q.catch((H)=>Ah||(Ah=H)),W.queue===N?J.push(Q):W.execute(Q)||D(W,N)}}function V(W){v=W,D(W,O),W.reserved=()=>J.length?W.execute(J.shift()):D(W,O)}}function D(_,j){return _.queue.remove(_),j.push(_),_.queue=j,j===Z?_.idleTimer.start():_.idleTimer.cancel(),_}function $h(_){return new th(_,3802)}function Oh(_,j){if(!Array.isArray(_))return Oh(Array.from(arguments));return new th(_,j||(_.length?dh(_)||25:0),f.shared.typeArrayMap)}function Lh(_){if(w)return _.reject(i.connection("CONNECTION_ENDED",f,f));if(Z.length)return gh(Z.shift(),_);if(S.length)return T(S.shift(),_);R.length?gh(R.shift(),_):E.push(_)}function gh(_,j){return _.execute(j)?D(_,R):D(_,N)}function Y(_){return new Promise((j,J)=>{_.state?_.active?Su(f).cancel(_.state,j,J):_.cancelled={resolve:j,reject:J}:(E.remove(_),_.cancelled=!0,_.reject(i.generic("57014","canceling statement due to user request")),j())})}async function $({timeout:_=null}={}){if(w)return w;await 1;let j;return w=Promise.race([new Promise((J)=>_!==null&&(j=setTimeout(s,_*1000,J))),Promise.all(C.map((J)=>J.end()).concat(z.sql?z.sql.end({timeout:0}):[],l.sql?l.sql.end({timeout:0}):[]))]).then(()=>clearTimeout(j))}async function _h(){await Promise.all(C.map((_)=>_.end()))}async function s(_){await Promise.all(C.map((j)=>j.terminate()));while(E.length)E.shift().reject(i.connection("CONNECTION_DESTROYED",f));_()}function T(_,j){return D(_,t),_.connect(j),_}function p(_){D(_,K)}function Dh(_){if(E.length===0)return D(_,Z);let j=Math.ceil(E.length/(t.length+1)),J=!0;while(J&&E.length&&j-- >0){let d=E.shift();if(d.reserve)return d.reserve(_);J=_.execute(d)}J?D(_,R):D(_,N)}function Eh(_,j){D(_,S),_.reserved=null,_.onclose&&(_.onclose(j),_.onclose=null),f.onclose&&f.onclose(_.id),E.length&&T(_,E.shift())}}function Bf(h,n){if(h&&h.shared)return h;let f=process.env,l=(!h||typeof h==="string"?n:h)||{},{url:w,multihost:E}=Mf(h),t=[...w.searchParams].reduce((N,[P,C])=>(N[P]=C,N),{}),O=l.hostname||l.host||E||w.hostname||f.PGHOST||"localhost",S=l.port||w.port||f.PGPORT||5432,K=l.user||l.username||w.username||f.PGUSERNAME||f.PGUSER||Nf();l.no_prepare&&(l.prepare=!1),t.sslmode&&(t.ssl=t.sslmode,delete t.sslmode),"timeout"in l&&(console.log("The timeout option is deprecated, use idle_timeout instead"),l.idle_timeout=l.timeout),t.sslrootcert==="system"&&(t.ssl="verify-full");let Z=["idle_timeout","connect_timeout","max_lifetime","max_pipeline","backoff","keep_alive"],R={max:globalThis.Cloudflare?3:10,ssl:!1,sslnegotiation:null,idle_timeout:null,connect_timeout:30,max_lifetime:gf,max_pipeline:100,backoff:Sf,keep_alive:60,prepare:!0,debug:!1,fetch_types:!0,publications:"alltables",target_session_attrs:null};return{host:Array.isArray(O)?O:O.split(",").map((N)=>N.split(":")[0]),port:Array.isArray(S)?S:O.split(",").map((N)=>parseInt(N.split(":")[1]||S)),path:l.path||O.indexOf("/")>-1&&O+"/.s.PGSQL."+S,database:l.database||l.db||(w.pathname||"").slice(1)||f.PGDATABASE||K,user:K,pass:l.pass||l.password||w.password||f.PGPASSWORD||"",...Object.entries(R).reduce((N,[P,C])=>{let g=P in l?l[P]:(P in t)?t[P]==="disable"||t[P]==="false"?!1:t[P]:f["PG"+P.toUpperCase()]||C;return N[P]=typeof g==="string"&&Z.includes(P)?+g:g,N},{}),connection:{application_name:f.PGAPPNAME||"postgres.js",...l.connection,...Object.entries(t).reduce((N,[P,C])=>((P in R)||(N[P]=C),N),{})},types:l.types||{},target_session_attrs:Gf(l,w,f),onnotice:l.onnotice,onnotify:l.onnotify,onclose:l.onclose,onparameter:l.onparameter,socket:l.socket,transform:jf(l.transform||{undefined:void 0}),parameters:{},shared:{retries:0,typeArrayMap:{}},...Wu(l.types)}}function Gf(h,n,f){let l=h.target_session_attrs||n.searchParams.get("target_session_attrs")||f.PGTARGETSESSIONATTRS;if(!l||["read-write","read-only","primary","standby","prefer-standby"].includes(l))return l;throw Error("target_session_attrs "+l+" is not supported")}function Sf(h){return(0.5+Math.random()/2)*Math.min(3**h/100,20)}function gf(){return 60*(30+Math.random()*30)}function jf(h){return{undefined:h.undefined,column:{from:typeof h.column==="function"?h.column:h.column&&h.column.from,to:h.column&&h.column.to},value:{from:typeof h.value==="function"?h.value:h.value&&h.value.from,to:h.value&&h.value.to},row:{from:typeof h.row==="function"?h.row:h.row&&h.row.from,to:h.row&&h.row.to}}}function Mf(h){if(!h||typeof h!=="string")return{url:{searchParams:new Map}};let n=h;n=n.slice(n.indexOf("://")+3).split(/[?/]/)[0],n=decodeURIComponent(n.slice(n.indexOf("@")+1));let f=new URL(h.replace(n,n.split(",")[0]));return{url:{username:decodeURIComponent(f.username),password:decodeURIComponent(f.password),host:f.host,hostname:f.hostname,port:f.port,pathname:f.pathname,searchParams:f.searchParams},multihost:n.indexOf(",")>-1&&n}}function Nf(){try{return Af.userInfo().username}catch(h){return process.env.USERNAME||process.env.USER||process.env.LOGNAME}}function ul(h){let n=yu(h);return{async setupTables(){await n`
45
+ CREATE TABLE IF NOT EXISTS sl_base_urls (
46
+ id SERIAL PRIMARY KEY,
47
+ base_url VARCHAR(255) NOT NULL UNIQUE,
48
+ is_active BOOLEAN DEFAULT TRUE,
49
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
50
+ )
51
+ `,await n`
52
+ CREATE TABLE IF NOT EXISTS sl_links_map (
53
+ id SERIAL PRIMARY KEY,
54
+ short_id VARCHAR(255) NOT NULL,
55
+ target_url TEXT NOT NULL,
56
+ base_url_id INT NULL,
57
+ last_accessed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
58
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
59
+ CONSTRAINT uk_short_id_base_url UNIQUE (short_id, base_url_id),
60
+ FOREIGN KEY (base_url_id) REFERENCES sl_base_urls(id) ON DELETE SET NULL
61
+ )
62
+ `,await n`
63
+ CREATE INDEX IF NOT EXISTS idx_sl_links_map_last_accessed_at
64
+ ON sl_links_map(last_accessed_at)
65
+ `,await n`
66
+ CREATE INDEX IF NOT EXISTS idx_sl_links_map_base_url_id
67
+ ON sl_links_map(base_url_id)
68
+ `,await n`
69
+ CREATE INDEX IF NOT EXISTS idx_sl_links_map_short_id_base_url
70
+ ON sl_links_map(short_id, base_url_id)
71
+ `},async getTargetUrl(f,l){return(l===null?await n`
72
+ SELECT target_url
73
+ FROM sl_links_map
74
+ WHERE short_id = ${f} AND base_url_id IS NULL
75
+ LIMIT 1
76
+ `:await n`
77
+ SELECT target_url
78
+ FROM sl_links_map
79
+ WHERE short_id = ${f} AND base_url_id = ${l}
80
+ LIMIT 1
81
+ `)[0]?.target_url??null},async createShortLink(f,l,w){await n`
82
+ INSERT INTO sl_links_map (short_id, target_url, base_url_id)
83
+ VALUES (${f}, ${l}, ${w})
84
+ `},async checkShortIdsExist(f,l){if(f.length===0)return[];let w=l===null?n`short_id IN ${n(f)} AND base_url_id IS NULL`:n`short_id IN ${n(f)} AND base_url_id = ${l}`;return(await n`
85
+ SELECT short_id
86
+ FROM sl_links_map
87
+ WHERE ${w}
88
+ `).map((t)=>t.short_id)},async updateShortLinkLastAccessTime(f,l,w=new Date){let E=w;if(typeof E==="number")E=new Date(E);let t=l===null?n`WHERE short_id = ${f} AND base_url_id IS NULL`:n`WHERE short_id = ${f} AND base_url_id = ${l}`;await n`
89
+ UPDATE sl_links_map
90
+ SET last_accessed_at = ${E}
91
+ ${t}
92
+ `},async cleanUnusedLinks(f){return(await n`
93
+ DELETE FROM sl_links_map
94
+ WHERE last_accessed_at < NOW() - make_interval(days => ${f})
95
+ RETURNING short_id, base_url_id
96
+ `).map((w)=>({shortId:w.short_id,baseUrlId:w.base_url_id}))},async removeShortLink(f,l){let w=l===null?n`WHERE short_id = ${f} AND base_url_id IS NULL`:n`WHERE short_id = ${f} AND base_url_id = ${l}`;await n`
97
+ DELETE FROM sl_links_map
98
+ ${w}
99
+ `},baseUrl:{async add(f){await n`
100
+ INSERT INTO sl_base_urls (base_url)
101
+ VALUES (${f})
102
+ ON CONFLICT (base_url) DO NOTHING
103
+ `},async remove(f){await n`
104
+ UPDATE sl_base_urls SET is_active = FALSE
105
+ WHERE id = ${f}
106
+ `},async list(f){return(f?await n`
107
+ SELECT id, base_url, is_active FROM sl_base_urls
108
+ `:await n`
109
+ SELECT id, base_url, is_active FROM sl_base_urls WHERE is_active = TRUE
110
+ `).map((w)=>({id:w.id,baseUrl:w.base_url,isActive:w.is_active}))},async getId(f){let l=await n`
111
+ SELECT id FROM sl_base_urls WHERE base_url = ${f} LIMIT 1
112
+ `;if(l.length===0)throw Error(`Base URL not found: ${f}`);return l[0].id}}}}var fl={};export{fl as default,ul as createPostgresBackend};
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@potonz/shortlinks-manager-postgres",
3
+ "description": "Short links manager extension for PostgreSQL using postgres.js",
4
+ "author": {
5
+ "name": "Thomas Nguyen",
6
+ "email": "tom@tomng.dev"
7
+ },
8
+ "homepage": "https://github.com/potonz/shortlinks-manager",
9
+ "repository": {
10
+ "url": "git+https://github.com/potonz/shortlinks-manager.git",
11
+ "type": "git",
12
+ "directory": "packages/shortlinks-manager-postgres"
13
+ },
14
+ "version": "0.3.0",
15
+ "type": "module",
16
+ "license": "MIT",
17
+ "dependencies": {
18
+ "@potonz/shortlinks-manager": "workspace:*",
19
+ "postgres": "^3.4.5"
20
+ },
21
+ "main": "./dist/index.js",
22
+ "module": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ ".": {
26
+ "import": "./dist/index.js",
27
+ "require": "./dist/index.js",
28
+ "types": "./dist/index.d.ts"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@potonz/shortlinks-manager-postgres",
3
+ "description": "Short links manager extension for PostgreSQL using postgres.js",
4
+ "author": {
5
+ "name": "Thomas Nguyen",
6
+ "email": "tom@tomng.dev"
7
+ },
8
+ "homepage": "https://github.com/potonz/shortlinks-manager",
9
+ "repository": {
10
+ "url": "git+https://github.com/potonz/shortlinks-manager.git",
11
+ "type": "git",
12
+ "directory": "packages/shortlinks-manager-postgres"
13
+ },
14
+ "version": "0.3.0",
15
+ "type": "module",
16
+ "license": "MIT",
17
+ "scripts": {
18
+ "test": "bun test"
19
+ },
20
+ "dependencies": {
21
+ "@potonz/shortlinks-manager": "0.2.3",
22
+ "postgres": "^3.4.5"
23
+ },
24
+ "devDependencies": {
25
+ "date-fns": "^4.1.0"
26
+ },
27
+ "main": "./dist/index.js",
28
+ "module": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ ".": {
32
+ "import": "./dist/index.js",
33
+ "require": "./dist/index.js",
34
+ "types": "./dist/index.d.ts"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist"
39
+ ],
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }