Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b86a4216cf | ||
|
|
57fefdc9e2 | ||
|
|
358958c127 | ||
|
|
c205ae81e2 | ||
|
|
0cec6414ae | ||
|
|
43173a833d |
No files matched your search
@@ -1,4 +1,11 @@
|
||||
# TODO
|
||||
push offers
|
||||
|
||||
listen / notify
|
||||
on offers
|
||||
notify admins
|
||||
|
||||
|
||||
contact options on landing page
|
||||
|
||||
move want add to rpc
|
||||
@@ -9,10 +16,3 @@ status stepper
|
||||
|
||||
queue up wantlist adds to gracefully handle rate limiting
|
||||
|
||||
push offers
|
||||
|
||||
listen / notify
|
||||
on offers
|
||||
notify admins
|
||||
|
||||
|
||||
+2
-2
@@ -26,10 +26,10 @@ async function start() {
|
||||
discogs,
|
||||
api,
|
||||
events,
|
||||
notify,
|
||||
} = createServices(log);
|
||||
|
||||
// events.emit(Events.Sync);
|
||||
// events.emit(Events.ListingsUpdated);
|
||||
await notify.connect();
|
||||
|
||||
api.listen();
|
||||
}
|
||||
|
||||
Generated
+336
-4
@@ -23,7 +23,8 @@
|
||||
"koa-websocket": "^7.0.0",
|
||||
"koa-ws": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"passport-local": "^1.0.0"
|
||||
"passport-local": "^1.0.0",
|
||||
"pg-listen": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
@@ -697,6 +698,15 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/bufferutil": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.1.0.tgz",
|
||||
@@ -2892,6 +2902,12 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/packet-reader": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
|
||||
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
|
||||
@@ -2991,6 +3007,129 @@
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
|
||||
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.5.2",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg-native": ">=3.0.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"pg-native": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/pg-format": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pg-format/-/pg-format-1.0.4.tgz",
|
||||
"integrity": "sha512-YyKEF78pEA6wwTAqOUaHIN/rWpfzzIuMh9KdAhc3rSLQ/7zkRFcCgYBAEGatDstLyZw4g0s9SNICmaTGnBVeyw==",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-listen": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-listen/-/pg-listen-1.7.0.tgz",
|
||||
"integrity": "sha512-MKDwKLm4ryhy7iq1yw1K1MvUzBdTkaT16HZToddX9QaT8XSdt3Kins5mYH6DLECGFzFWG09VdXvWOIYogjXrsg==",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"pg-format": "^1.0.4",
|
||||
"typed-emitter": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"pg": "7.x || 8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-listen/node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/pg-listen/node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/pg-pool": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz",
|
||||
"integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"pg": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pgpass": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"split2": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
@@ -3003,6 +3142,45 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-bytea": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"xtend": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prisma": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz",
|
||||
@@ -3234,6 +3412,15 @@
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/split2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
|
||||
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -3483,6 +3670,11 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/typed-emitter": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-0.1.0.tgz",
|
||||
"integrity": "sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.7.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
|
||||
@@ -3636,7 +3828,6 @@
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
@@ -4276,6 +4467,12 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"buffer-writer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
|
||||
"integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==",
|
||||
"peer": true
|
||||
},
|
||||
"bufferutil": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.1.0.tgz",
|
||||
@@ -5891,6 +6088,12 @@
|
||||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"packet-reader": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz",
|
||||
"integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==",
|
||||
"peer": true
|
||||
},
|
||||
"parse5": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.0.0.tgz",
|
||||
@@ -5962,12 +6165,131 @@
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||
},
|
||||
"pg": {
|
||||
"version": "8.8.0",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz",
|
||||
"integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
"pg-connection-string": "^2.5.0",
|
||||
"pg-pool": "^3.5.2",
|
||||
"pg-protocol": "^1.5.0",
|
||||
"pg-types": "^2.1.0",
|
||||
"pgpass": "1.x"
|
||||
}
|
||||
},
|
||||
"pg-connection-string": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz",
|
||||
"integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==",
|
||||
"peer": true
|
||||
},
|
||||
"pg-format": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pg-format/-/pg-format-1.0.4.tgz",
|
||||
"integrity": "sha512-YyKEF78pEA6wwTAqOUaHIN/rWpfzzIuMh9KdAhc3rSLQ/7zkRFcCgYBAEGatDstLyZw4g0s9SNICmaTGnBVeyw=="
|
||||
},
|
||||
"pg-int8": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
|
||||
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
|
||||
"peer": true
|
||||
},
|
||||
"pg-listen": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-listen/-/pg-listen-1.7.0.tgz",
|
||||
"integrity": "sha512-MKDwKLm4ryhy7iq1yw1K1MvUzBdTkaT16HZToddX9QaT8XSdt3Kins5mYH6DLECGFzFWG09VdXvWOIYogjXrsg==",
|
||||
"requires": {
|
||||
"debug": "^4.1.1",
|
||||
"pg-format": "^1.0.4",
|
||||
"typed-emitter": "^0.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"pg-pool": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz",
|
||||
"integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==",
|
||||
"peer": true,
|
||||
"requires": {}
|
||||
},
|
||||
"pg-protocol": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz",
|
||||
"integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==",
|
||||
"peer": true
|
||||
},
|
||||
"pg-types": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
|
||||
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"pg-int8": "1.0.1",
|
||||
"postgres-array": "~2.0.0",
|
||||
"postgres-bytea": "~1.0.0",
|
||||
"postgres-date": "~1.0.4",
|
||||
"postgres-interval": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"pgpass": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
|
||||
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"split2": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true
|
||||
},
|
||||
"postgres-array": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
|
||||
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
|
||||
"peer": true
|
||||
},
|
||||
"postgres-bytea": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
|
||||
"integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
|
||||
"peer": true
|
||||
},
|
||||
"postgres-date": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
|
||||
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
|
||||
"peer": true
|
||||
},
|
||||
"postgres-interval": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
|
||||
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"prisma": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz",
|
||||
@@ -6138,6 +6460,12 @@
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"split2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
|
||||
"integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
|
||||
"peer": true
|
||||
},
|
||||
"statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -6304,6 +6632,11 @@
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typed-emitter": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-0.1.0.tgz",
|
||||
"integrity": "sha512-Tfay0l6gJMP5rkil8CzGbLthukn+9BN/VXWcABVFPjOoelJ+koW8BuPZYk+h/L+lEeIp1fSzVRiWRPIjKVjPdg=="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.7.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
|
||||
@@ -6427,8 +6760,7 @@
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@
|
||||
"koa-websocket": "^7.0.0",
|
||||
"koa-ws": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"passport-local": "^1.0.0"
|
||||
"passport-local": "^1.0.0",
|
||||
"pg-listen": "^1.7.0"
|
||||
},
|
||||
"overrides": {
|
||||
"koa-passport": {
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "listings" (
|
||||
"id" BIGINT NOT NULL,
|
||||
"seller" BIGINT NOT NULL,
|
||||
"data" JSONB NOT NULL,
|
||||
"wantId" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "listings_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "wants" (
|
||||
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
||||
"release" BIGINT NOT NULL,
|
||||
"data" JSONB NOT NULL,
|
||||
"userId" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "wants_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "offers" (
|
||||
"id" UUID NOT NULL DEFAULT gen_random_uuid(),
|
||||
"status" TEXT NOT NULL,
|
||||
"condition" TEXT NOT NULL DEFAULT '',
|
||||
"item" MONEY NOT NULL,
|
||||
"shipping" MONEY NOT NULL,
|
||||
"total" MONEY NOT NULL,
|
||||
"listingId" BIGINT NOT NULL,
|
||||
"userId" UUID NOT NULL,
|
||||
"wantId" UUID NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "offers_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "listings_seller_idx" ON "listings"("seller");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "wants_release_idx" ON "wants"("release");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "wants_userId_release_key" ON "wants"("userId", "release");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "offers_listingId_key" ON "offers"("listingId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "listings" ADD CONSTRAINT "listings_wantId_fkey" FOREIGN KEY ("wantId") REFERENCES "wants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "wants" ADD CONSTRAINT "wants_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "offers" ADD CONSTRAINT "offers_listingId_fkey" FOREIGN KEY ("listingId") REFERENCES "listings"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "offers" ADD CONSTRAINT "offers_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "offers" ADD CONSTRAINT "offers_wantId_fkey" FOREIGN KEY ("wantId") REFERENCES "wants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,111 @@
|
||||
CREATE OR REPLACE FUNCTION notify_users() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
record RECORD;
|
||||
id UUID;
|
||||
payload JSON;
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
id = OLD.id;
|
||||
ELSE
|
||||
id = NEW.id;
|
||||
END IF;
|
||||
|
||||
payload = json_build_object(
|
||||
'table', TG_TABLE_NAME,
|
||||
'action', TG_OP,
|
||||
'id', id
|
||||
);
|
||||
|
||||
PERFORM pg_notify('users.events', payload::text);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_listings() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
record RECORD;
|
||||
id int8;
|
||||
payload JSON;
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
id = OLD.id;
|
||||
ELSE
|
||||
id = NEW.id;
|
||||
END IF;
|
||||
|
||||
payload = json_build_object(
|
||||
'table', TG_TABLE_NAME,
|
||||
'action', TG_OP,
|
||||
'id', id
|
||||
);
|
||||
|
||||
PERFORM pg_notify('listings.events', payload::text);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_offers() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
record RECORD;
|
||||
id UUID;
|
||||
payload JSON;
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
id = OLD.id;
|
||||
ELSE
|
||||
id = NEW.id;
|
||||
END IF;
|
||||
|
||||
payload = json_build_object(
|
||||
'table', TG_TABLE_NAME,
|
||||
'action', TG_OP,
|
||||
'id', id
|
||||
);
|
||||
|
||||
PERFORM pg_notify('offers.events', payload::text);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION notify_wants() RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
record RECORD;
|
||||
id UUID;
|
||||
payload JSON;
|
||||
BEGIN
|
||||
IF (TG_OP = 'DELETE') THEN
|
||||
id = OLD.id;
|
||||
ELSE
|
||||
id = NEW.id;
|
||||
END IF;
|
||||
|
||||
payload = json_build_object(
|
||||
'table', TG_TABLE_NAME,
|
||||
'action', TG_OP,
|
||||
'id', id
|
||||
);
|
||||
|
||||
PERFORM pg_notify('wants.events', payload::text);
|
||||
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE TRIGGER notify_wants_event
|
||||
AFTER INSERT OR UPDATE OR DELETE ON wants
|
||||
FOR EACH ROW EXECUTE PROCEDURE notify_wants();
|
||||
|
||||
CREATE OR REPLACE TRIGGER notify_listings_event
|
||||
AFTER INSERT OR UPDATE OR DELETE ON listings
|
||||
FOR EACH ROW EXECUTE PROCEDURE notify_listings();
|
||||
|
||||
CREATE OR REPLACE TRIGGER notify_offers_event
|
||||
AFTER INSERT OR UPDATE OR DELETE ON offers
|
||||
FOR EACH ROW EXECUTE PROCEDURE notify_offers();
|
||||
|
||||
CREATE OR REPLACE TRIGGER notify_users_event
|
||||
AFTER INSERT OR UPDATE OR DELETE ON users
|
||||
FOR EACH ROW EXECUTE PROCEDURE notify_users();
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
+2
-1
@@ -109,7 +109,6 @@ export default function createApi(log: Log, pg: Pg, discogs: Discogs, offers: Of
|
||||
const ws = ctx.websocket;
|
||||
const rpc = createRpc(log, pg, ws, discogs, offers, events, ctx.state.user as User | null);
|
||||
|
||||
if (ctx.state.user) events.emit(Events.Connection, { ws, id: ctx.state.user.id });
|
||||
ws.on('message', async function incoming(message) {
|
||||
try {
|
||||
const parsed = JSON.parse(message.toString());
|
||||
@@ -127,7 +126,9 @@ export default function createApi(log: Log, pg: Pg, discogs: Discogs, offers: Of
|
||||
log.info('ws disconnected', { user: ctx.state.user });
|
||||
});
|
||||
|
||||
if (ctx.state.user) events.emit(Events.Connection, { rpc, id: ctx.state.user.id });
|
||||
await rpc.onConnection();
|
||||
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
|
||||
+15
-4
@@ -2,9 +2,10 @@ import { EventEmitter } from 'node:events';
|
||||
import { setTimeout } from 'timers/promises';
|
||||
|
||||
import type Log from 'bunyan';
|
||||
import type { Want } from '@prisma/client';
|
||||
import type { Want, Offer } from '@prisma/client';
|
||||
|
||||
import { Pg } from './pg';
|
||||
import { Rpc } from './rpc';
|
||||
import { wantDetails } from './utils';
|
||||
import routerAuth from './routers/router.auth';
|
||||
|
||||
@@ -13,11 +14,13 @@ export enum Events {
|
||||
Sync = 'Sync',
|
||||
ListingsUpdated = 'ListingsUpdated',
|
||||
Connection = 'Connection',
|
||||
|
||||
OffersUpdated = 'OffersUpdated'
|
||||
}
|
||||
|
||||
export default function createEvents(log: Log, pg: Pg, discogs, offers) {
|
||||
const events = new EventEmitter({ captureRejections: true });
|
||||
const connections = new Map();
|
||||
const connections = new Map<UUID, Rpc>();
|
||||
|
||||
async function populateListings(want: Want) {
|
||||
try {
|
||||
@@ -66,9 +69,17 @@ export default function createEvents(log: Log, pg: Pg, discogs, offers) {
|
||||
log.debug({ offers: updatedOffers.length }, 'offers up to date');
|
||||
});
|
||||
|
||||
events.on(Events.Connection, async function onConnection({ ws, id }) {
|
||||
connections.set(id, ws);
|
||||
events.on(Events.Connection, async function onConnection({ rpc, id }) {
|
||||
log.debug('new rpc connection', { id, rpc });
|
||||
connections.set(id, rpc);
|
||||
})
|
||||
|
||||
events.on(Events.OffersUpdated, async function onOffersUpdated(offer: Offer) {
|
||||
const rpc = connections.get(offer.userId);
|
||||
if (!rpc) return null;
|
||||
log.debug({ event: Events.OffersUpdated, rpc, offer });
|
||||
return rpc.sendUserOffers();
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import createSubscriber from 'pg-listen'
|
||||
import type Log from 'bunyan';
|
||||
|
||||
import { Events } from './events';
|
||||
|
||||
export default function createNotify(log: Log, events) {
|
||||
const CHANNEL = 'events';
|
||||
const subscriber = createSubscriber({ connectionString: process.env.DATABASE_URL });
|
||||
|
||||
subscriber.notifications.on(CHANNEL, ({ table, action, record }) => {
|
||||
if (table === 'offers') return events.emit(Events.OffersUpdated, record);
|
||||
})
|
||||
|
||||
async function connect() {
|
||||
await subscriber.connect();
|
||||
return subscriber.listenTo(CHANNEL);
|
||||
}
|
||||
|
||||
return { connect };
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import createSubscriber from 'pg-listen'
|
||||
import type Log from 'bunyan';
|
||||
|
||||
import { Events } from './events';
|
||||
import { Pg } from './pg';
|
||||
|
||||
export default function createNotify(log: Log, pg: Pg, events) {
|
||||
const OFFERS_CHANNEL = 'offers.events';
|
||||
const USERS_CHANNEL = 'users.events';
|
||||
const LISTINGS_CHANNEL = 'listings.events';
|
||||
const WANTS_CHANNEL = 'wants.events';
|
||||
|
||||
const subscriber = createSubscriber({ connectionString: process.env.DATABASE_URL });
|
||||
|
||||
// pg has a hard limit of 8000B for the notification payload
|
||||
// so we only receive the ids of the updated record
|
||||
// and go fetch the whole thing to figure out who to notify
|
||||
|
||||
async function handleOffers(payload) {
|
||||
const { action, id } = payload;
|
||||
log.info({ channel: OFFERS_CHANNEL, action, id });
|
||||
}
|
||||
|
||||
async function handleUsers(payload) {
|
||||
const { action, id } = payload;
|
||||
log.info({ channel: USERS_CHANNEL, action, id });
|
||||
}
|
||||
|
||||
async function handleListings(payload) {
|
||||
const { action, id } = payload;
|
||||
log.info({ channel: LISTINGS_CHANNEL, action, id });
|
||||
}
|
||||
|
||||
async function handleWants(payload) {
|
||||
const { action, id } = payload;
|
||||
log.info({ channel: WANTS_CHANNEL, action, id });
|
||||
}
|
||||
|
||||
subscriber.notifications.on(OFFERS_CHANNEL, handleOffers);
|
||||
subscriber.notifications.on(USERS_CHANNEL, handleUsers);
|
||||
subscriber.notifications.on(LISTINGS_CHANNEL, handleListings);
|
||||
subscriber.notifications.on(WANTS_CHANNEL, handleWants);
|
||||
|
||||
async function connect() {
|
||||
await subscriber.connect();
|
||||
await Promise.all([
|
||||
subscriber.listenTo(OFFERS_CHANNEL),
|
||||
subscriber.listenTo(USERS_CHANNEL),
|
||||
subscriber.listenTo(LISTINGS_CHANNEL),
|
||||
subscriber.listenTo(WANTS_CHANNEL),
|
||||
]);
|
||||
}
|
||||
|
||||
return { connect };
|
||||
}
|
||||
+10
-11
@@ -131,8 +131,8 @@ export default function createPg(log: Log, prisma: PrismaClient) {
|
||||
|
||||
const protectedOfferStatuses = [Status.Confirmed, Status.Complete];
|
||||
|
||||
// can't delete a listing with an open offer
|
||||
// so delete those offers first
|
||||
// delete all the offers where we don't want to keep them
|
||||
// for historical reasons
|
||||
const { count: offersRemoved } = await prisma.offer.deleteMany({
|
||||
where: {
|
||||
wantId: want.id,
|
||||
@@ -145,7 +145,7 @@ export default function createPg(log: Log, prisma: PrismaClient) {
|
||||
}
|
||||
});
|
||||
|
||||
if (offersRemoved > 0) log.info({ offersRemoved }, 'open offers removed');
|
||||
if (offersRemoved > 0) log.info({ offersRemoved }, 'pending offers removed');
|
||||
|
||||
// now we have to filter listingIds with confirmed offers
|
||||
// and get their listingIds to filter out
|
||||
@@ -154,23 +154,22 @@ export default function createPg(log: Log, prisma: PrismaClient) {
|
||||
wantId: want.id,
|
||||
status: {
|
||||
in: protectedOfferStatuses,
|
||||
}
|
||||
},
|
||||
},
|
||||
select: {
|
||||
listingId: true,
|
||||
}
|
||||
},
|
||||
})).map(r => r.listingId);
|
||||
const removalIds = _.without(currentListingIds, ...confirmedListingIds);
|
||||
const removalIds = currentListingIds.filter(id => confirmedListingIds.includes(id));
|
||||
|
||||
if (removalIds.length) log.info({ removalIds });
|
||||
|
||||
// finally we delete listings that aren't related
|
||||
// to a historical offer
|
||||
const { count } = await prisma.listing.deleteMany({
|
||||
where: {
|
||||
wantId: want.id,
|
||||
id: {
|
||||
notIn: currentListingIds,
|
||||
}
|
||||
}
|
||||
id: { in: removalIds },
|
||||
},
|
||||
});
|
||||
|
||||
log.info({ count }, 'second stage open offers removed');
|
||||
|
||||
+9
-3
@@ -134,9 +134,7 @@ export default function createRpc(log: Log, pg: Pg, ws, discogs: Discogs, offers
|
||||
const userMsg: UserMessage = [RpcMessageType.User, user];
|
||||
send(userMsg);
|
||||
|
||||
const userOffers = await offers.userOffers(user);
|
||||
const offersMsg: OffersMessage = [RpcMessageType.Offers, userOffers];
|
||||
send(offersMsg);
|
||||
await sendUserOffers();
|
||||
|
||||
const wants = await pg.userWants(user);
|
||||
const wantsMsg: WantsMessage = [RpcMessageType.Wants, wants];
|
||||
@@ -153,10 +151,18 @@ export default function createRpc(log: Log, pg: Pg, ws, discogs: Discogs, offers
|
||||
))
|
||||
}
|
||||
|
||||
async function sendUserOffers() {
|
||||
const userOffers = await offers.userOffers(user);
|
||||
const offersMsg: OffersMessage = [RpcMessageType.Offers, userOffers];
|
||||
send(offersMsg);
|
||||
}
|
||||
|
||||
return {
|
||||
receive,
|
||||
send,
|
||||
onConnection,
|
||||
|
||||
sendUserOffers,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -6,19 +6,22 @@ import createLog from './log';
|
||||
import createApi from './api';
|
||||
import createEvents from './events';
|
||||
import createPg from './pg';
|
||||
import createNotify from './notify';
|
||||
|
||||
export default function creates(log) {
|
||||
export default function createServices(log) {
|
||||
const prisma = new PrismaClient();
|
||||
const pg = createPg(log, prisma);
|
||||
const discogs = createDiscogs(log, pg);
|
||||
const offers = createOffers(log, pg);
|
||||
const events = createEvents(log, pg, discogs, offers);
|
||||
const notify = createNotify(log, pg, events);
|
||||
const api = createApi(log, pg, discogs, offers, events);
|
||||
|
||||
return {
|
||||
api,
|
||||
discogs,
|
||||
events,
|
||||
notify,
|
||||
pg,
|
||||
prisma,
|
||||
};
|
||||
|
||||
@@ -33,6 +33,8 @@ const Main = () => {
|
||||
const { ws } = store.getState();
|
||||
if (!ws) return null;
|
||||
if (e.url === '/acp') return ws.sendAcpOffers();
|
||||
if (e.url === '/') return ws.sendOffers();
|
||||
if (e.url === '/list') return ws.sendWants();
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -58,12 +58,16 @@ function OfferPriceBtn(offer) {
|
||||
export default function OfferGroup(group, i) {
|
||||
const ws = useSelector((state: State) => state.ws);
|
||||
|
||||
const format = group.details.formats[0].text ? `${group.details.formats[0].text} - ` : '';
|
||||
const descriptions = group.details.formats.map(f => f.descriptions.join(' ')).join(' ')
|
||||
const detailText = `${format} ${descriptions}`;
|
||||
|
||||
return (
|
||||
<div class="offer" key={i}>
|
||||
<section>
|
||||
<h3>{group.details.artists_sort} - {group.details.title} <a href={group.details.uri} target="_blank"><ExternalLink /></a></h3>
|
||||
<div class='alt-text details'>
|
||||
{group.details.year} - {group.details.formats.map(f => f.descriptions.join(' ')).join(' ')}
|
||||
{group.details.year} - {detailText}
|
||||
</div>
|
||||
<div class='alt-text details'>Status: {group.status}</div>
|
||||
</section>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { wantsState, wsState, userState, offersState, acpOffersState } from './store'
|
||||
|
||||
import * as toast from './toast';
|
||||
|
||||
const SOCKET_URL = `${window.location.protocol === 'https:' ? 'wss://' : 'ws://'}${window.location.host}/api/ws`;
|
||||
|
||||
export default function createSocket(dispatch) {
|
||||
@@ -155,6 +157,7 @@ export default function createSocket(dispatch) {
|
||||
sendWantRm,
|
||||
|
||||
sendOffers,
|
||||
sendWants,
|
||||
|
||||
sendAcpOffers,
|
||||
sendAcpOfferStatusSet,
|
||||
|
||||
Reference in new issue
Block a user