mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 16:55:37 +02:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5b3043436 | ||
|
|
623a0db97f | ||
|
|
9827100d19 | ||
|
|
88f499ba5e | ||
|
|
0a1a4cd9b6 | ||
|
|
d7cb47fdd6 | ||
|
|
8b07adb0fc | ||
|
|
661d9d2e56 | ||
|
|
6eee40fcbe | ||
|
|
69d728c4a9 | ||
|
|
be85594bdc | ||
|
|
6e82eff9e2 | ||
|
|
e67a8d2b32 | ||
|
|
8f4bb05143 | ||
|
|
84357ac5bf | ||
|
|
e11012e8d9 | ||
|
|
c0194ecef4 | ||
|
|
ae364f69bd | ||
|
|
d7e6da12ac | ||
|
|
6e19b2e9a0 | ||
|
|
dd20c0049d | ||
|
|
14e4176344 | ||
|
|
baf178afc5 | ||
|
|
80deb82d25 | ||
|
|
e1a903a7c9 | ||
|
|
cc2065299d | ||
|
|
0cc9effdec | ||
|
|
82dfd6506d | ||
|
|
6051e11921 | ||
|
|
86670d5931 | ||
|
|
35f009e925 | ||
|
|
5806dc6e86 | ||
|
|
38ad74d14a | ||
|
|
0b995fa540 | ||
|
|
d933c1e61d | ||
|
|
b86fc625ba | ||
|
|
c250fd557c | ||
|
|
1923cdf2a3 | ||
|
|
7e69af977b | ||
|
|
70d629227a | ||
|
|
a0dc353561 | ||
|
|
47e61599bb | ||
|
|
76d27e4708 | ||
|
|
896832b89c | ||
|
|
492013d610 | ||
|
|
e93099784c | ||
|
|
9a6826b069 | ||
|
|
f408ec56cb | ||
|
|
8394bb4259 | ||
|
|
0305a14fdd | ||
|
|
6b1521d7d4 | ||
|
|
39e187832a | ||
|
|
de80f3e6ab | ||
|
|
6990494b34 | ||
|
|
5a3fdf25ff | ||
|
|
18b14a4261 | ||
|
|
f4aa2ca4a4 | ||
|
|
6092c4e4f8 | ||
|
|
f3d7ea2663 | ||
|
|
7ff4ff8c90 | ||
|
|
7ecc068466 | ||
|
|
633b332700 | ||
|
|
cacdae79c0 | ||
|
|
ca4432bcde | ||
|
|
261a1276f5 | ||
|
|
a45b2bf9b7 | ||
|
|
f62fc1fb4b | ||
|
|
957eca7794 |
26
.github/PULL_REQUEST_TEMPLATE.md
vendored
26
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,28 +1,2 @@
|
|||||||
## Description
|
## Description
|
||||||
<!-- Briefly describe the purpose and scope of your changes -->
|
<!-- Briefly describe the purpose and scope of your changes -->
|
||||||
|
|
||||||
## Related Issues
|
|
||||||
<!-- List any related issues (e.g., "Closes #123", "Fixes #456") -->
|
|
||||||
|
|
||||||
## Type of Change
|
|
||||||
|
|
||||||
- [ ] Bug fix (non-breaking change)
|
|
||||||
- [ ] New feature (non-breaking change)
|
|
||||||
- [ ] Breaking change (fix or feature that changes existing functionality)
|
|
||||||
- [ ] Documentation update
|
|
||||||
- [ ] Other (please describe):
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
|
|
||||||
- [ ] I have updated relevant documentation
|
|
||||||
- [ ] My code follows the project's coding style
|
|
||||||
- [ ] My changes generate no new warnings/errors
|
|
||||||
|
|
||||||
## Notes for Reviewers
|
|
||||||
<!-- Point out areas you'd like reviewers to focus on, questions you have, or decisions that need discussion -->
|
|
||||||
|
|
||||||
## Screenshots/Demo
|
|
||||||
<!-- If applicable, add screenshots or a GIF demo of your changes (especially for UI changes) -->
|
|
||||||
|
|
||||||
## Additional Context
|
|
||||||
<!-- Add any other context about the pull request here -->
|
|
||||||
40
.github/workflows/docs.yml
vendored
Normal file
40
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "apps/docs/**"
|
||||||
|
- ".github/workflows/docs.yml"
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "apps/docs/**"
|
||||||
|
- ".github/workflows/docs.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-docs:
|
||||||
|
name: Build and deploy docs
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: "apps/docs"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install
|
||||||
|
- name: Build Project Artifacts
|
||||||
|
run: bun run build
|
||||||
|
- name: Deploy Project Artifacts to Cloudflare
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
packageManager: bun
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
wranglerVersion: "3.93.0"
|
||||||
|
workingDirectory: "apps/docs"
|
||||||
|
command: pages deploy ./dist --project-name=${{ vars.CF_DOCS_PAGES_PROJECT_NAME }} --commit-dirty=true
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
6
.github/workflows/runner.yml
vendored
6
.github/workflows/runner.yml
vendored
@@ -27,6 +27,7 @@ env:
|
|||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
IMAGE_NAME: nestrilabs/nestri
|
IMAGE_NAME: nestrilabs/nestri
|
||||||
BASE_TAG_PREFIX: runner
|
BASE_TAG_PREFIX: runner
|
||||||
|
BASE_IMAGE: docker.io/cachyos/cachyos:latest
|
||||||
|
|
||||||
# This makes our release ci quit prematurely
|
# This makes our release ci quit prematurely
|
||||||
# concurrency:
|
# concurrency:
|
||||||
@@ -55,7 +56,7 @@ jobs:
|
|||||||
swap-size-gb: 20
|
swap-size-gb: 20
|
||||||
-
|
-
|
||||||
name: Build Docker image
|
name: Build Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
file: containers/runner.Containerfile
|
file: containers/runner.Containerfile
|
||||||
context: ./
|
context: ./
|
||||||
@@ -107,7 +108,7 @@ jobs:
|
|||||||
swap-size-gb: 20
|
swap-size-gb: 20
|
||||||
-
|
-
|
||||||
name: Build Docker image
|
name: Build Docker image
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
file: containers/runner.Containerfile
|
file: containers/runner.Containerfile
|
||||||
context: ./
|
context: ./
|
||||||
@@ -116,3 +117,4 @@ jobs:
|
|||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
cache-from: type=gha,mode=max
|
cache-from: type=gha,mode=max
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
pull: ${{ github.event_name == 'schedule' }} # Pull base image for scheduled builds
|
||||||
|
|||||||
40
.github/workflows/www.yml
vendored
Normal file
40
.github/workflows/www.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build www
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "apps/www/**"
|
||||||
|
- ".github/workflows/www.yml"
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "apps/www/**"
|
||||||
|
- ".github/workflows/www.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-www:
|
||||||
|
name: Build and deploy www
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: "apps/www"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: oven-sh/setup-bun@v1
|
||||||
|
with:
|
||||||
|
bun-version: latest
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install
|
||||||
|
- name: Build Project Artifacts
|
||||||
|
run: bun run build
|
||||||
|
- name: Deploy Project Artifacts to Cloudflare
|
||||||
|
uses: cloudflare/wrangler-action@v3
|
||||||
|
with:
|
||||||
|
packageManager: bun
|
||||||
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||||
|
wranglerVersion: "3.93.0"
|
||||||
|
workingDirectory: "apps/www"
|
||||||
|
command: pages deploy ./dist --project-name=${{ vars.CF_WWW_PAGES_PROJECT_NAME }} --commit-dirty=true
|
||||||
|
env:
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
|
}
|
||||||
3843
apps/docs/package-lock.json
generated
3843
apps/docs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,19 +4,19 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"nestri.dev": "nuxi dev",
|
"nestri.dev": "nuxi dev",
|
||||||
"build": "nuxi build",
|
"build": "nuxi build --preset=cloudflare_pages",
|
||||||
"generate": "nuxi generate",
|
"generate": "nuxi generate",
|
||||||
"preview": "nuxi preview",
|
"preview": "nuxi preview",
|
||||||
"lint": "eslint ."
|
"lint": "eslint ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt-themes/docus": "latest",
|
"@nuxt-themes/docus": "latest",
|
||||||
"@nuxt/devtools": "^1.4.1",
|
"@nuxt/devtools": "^2.3.2",
|
||||||
"@nuxt/eslint-config": "^0.5.6",
|
"@nuxt/eslint-config": "^0.5.6",
|
||||||
"@nuxt/ui": "^2.19.2",
|
"@nuxt/ui": "^2.19.2",
|
||||||
"@nuxtjs/plausible": "^1.0.2",
|
"@nuxtjs/plausible": "^1.0.2",
|
||||||
"@types/node": "^20.16.5",
|
"@types/node": "^20.16.5",
|
||||||
"eslint": "^9.10.0",
|
"eslint": "^9.10.0",
|
||||||
"nuxt": "^3.15.4"
|
"nuxt": "^3.16.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"@nestri/libmoq": "*",
|
"@nestri/libmoq": "*",
|
||||||
"@nestri/sdk": "0.1.0-alpha.14",
|
"@nestri/sdk": "0.1.0-alpha.14",
|
||||||
"@nestri/ui": "*",
|
"@nestri/ui": "*",
|
||||||
"@openauthjs/openauth": "^0.2.6",
|
"@openauthjs/openauth": "*",
|
||||||
"@polar-sh/checkout": "^0.1.8",
|
"@polar-sh/checkout": "^0.1.8",
|
||||||
"@polar-sh/sdk": "^0.21.1",
|
"@polar-sh/sdk": "^0.21.1",
|
||||||
"@qwik-ui/headless": "^0.6.4",
|
"@qwik-ui/headless": "^0.6.4",
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
"typescript": "5.4.5",
|
"typescript": "5.4.5",
|
||||||
"undici": "*",
|
"undici": "*",
|
||||||
"valibot": "^0.42.1",
|
"valibot": "^0.42.1",
|
||||||
"vite": "5.4.12",
|
"vite": "6.0.15",
|
||||||
"vite-tsconfig-paths": "^4.2.1",
|
"vite-tsconfig-paths": "^4.2.1",
|
||||||
"wrangler": "^3.0.0"
|
"wrangler": "^3.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default component$(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const lockPlay = $(async () => {
|
const lockPlay = $(async () => {
|
||||||
if (!canvas.value || !playState.hasStream) return;
|
if (!canvas.value || !playState.hasStream || playState.nestriLock) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await canvas.value.requestPointerLock();
|
await canvas.value.requestPointerLock();
|
||||||
@@ -156,18 +156,22 @@ export default component$(() => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line qwik/no-use-visible-task
|
// eslint-disable-next-line qwik/no-use-visible-task
|
||||||
useVisibleTask$(({ track }) => {
|
useVisibleTask$(({ track }) => {
|
||||||
track(() => canvas.value);
|
track(() => canvas.value);
|
||||||
if (!canvas.value) return; // Ensure canvas is available
|
if (!canvas.value) return; // Ensure canvas is available
|
||||||
|
// Get query parameter "peerURL" from the URL
|
||||||
|
let peerURL = new URLSearchParams(window.location.search).get("peerURL");
|
||||||
|
if (!peerURL || peerURL.length <= 0) {
|
||||||
|
peerURL = "/dnsaddr/relay.dathorse.com/p2p/12D3KooWPK4v5wKYNYx9oXWjqLM8Xix6nm13o91j1Feqq98fLBsw";
|
||||||
|
}
|
||||||
|
|
||||||
setupPointerLockListener();
|
setupPointerLockListener();
|
||||||
try {
|
try {
|
||||||
if (!playState.video) {
|
if (!playState.video) {
|
||||||
playState.video = document.createElement("video") as HTMLVideoElement
|
playState.video = document.createElement("video") as HTMLVideoElement;
|
||||||
playState.video.style.visibility = "hidden";
|
playState.video.style.visibility = "hidden";
|
||||||
playState.webrtc = noSerialize(new WebRTCStream("https://relay.dathorse.com", id, async (mediaStream) => {
|
playState.webrtc = noSerialize(new WebRTCStream(peerURL, id, async (mediaStream) => {
|
||||||
if (playState.video && mediaStream && playState.video.srcObject === null) {
|
if (playState.video && mediaStream && playState.video.srcObject === null) {
|
||||||
console.log("Setting mediastream");
|
console.log("Setting mediastream");
|
||||||
playState.video.srcObject = mediaStream;
|
playState.video.srcObject = mediaStream;
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ export default component$(() => {
|
|||||||
<div class="w-screen relative">
|
<div class="w-screen relative">
|
||||||
<HeroSection client:load>
|
<HeroSection client:load>
|
||||||
<div class="sm:w-full flex gap-3 justify-center pt-4 sm:flex-row flex-col w-auto items-center">
|
<div class="sm:w-full flex gap-3 justify-center pt-4 sm:flex-row flex-col w-auto items-center">
|
||||||
<Link href="/auth/login" prefetch={false} class="flex ring-2 ring-primary-500 font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
<Link href="https://discord.gg/6um5K6jrYj" prefetch={false} class="flex ring-2 ring-primary-500 font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
||||||
Get early access
|
Join our Discord
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="/links/github" prefetch={false} class="sm:flex text-sm sm:text-base hidden font-bricolage items-center gap-2 rounded-full font-semibold text-gray-900/70 dark:text-gray-100/70 bg-white dark:bg-black px-5 py-4 ring-2 ring-gray-300 dark:ring-gray-700 transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
<Link href="/links/github" prefetch={false} class="sm:flex text-sm sm:text-base hidden font-bricolage items-center gap-2 rounded-full font-semibold text-gray-900/70 dark:text-gray-100/70 bg-white dark:bg-black px-5 py-4 ring-2 ring-gray-300 dark:ring-gray-700 transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-5 w-5 fill-content3-light"><path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" class="h-5 w-5 fill-content3-light"><path fill-rule="evenodd" d="M4.25 5.5a.75.75 0 00-.75.75v8.5c0 .414.336.75.75.75h8.5a.75.75 0 00.75-.75v-4a.75.75 0 011.5 0v4A2.25 2.25 0 0112.75 17h-8.5A2.25 2.25 0 012 14.75v-8.5A2.25 2.25 0 014.25 4h5a.75.75 0 010 1.5h-5z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M6.194 12.753a.75.75 0 001.06.053L16.5 4.44v2.81a.75.75 0 001.5 0v-4.5a.75.75 0 00-.75-.75h-4.5a.75.75 0 000 1.5h2.553l-9.056 8.194a.75.75 0 00-.053 1.06z" clip-rule="evenodd"></path></svg>
|
||||||
@@ -570,8 +570,8 @@ export default component$(() => {
|
|||||||
</section>
|
</section>
|
||||||
<Footer client:load>
|
<Footer client:load>
|
||||||
<div class="w-full flex justify-center flex-col items-center gap-3">
|
<div class="w-full flex justify-center flex-col items-center gap-3">
|
||||||
<Link href="/auth/login" prefetch={false} class="ring-2 ring-primary-500 flex font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
<Link href="https://discord.gg/6um5K6jrYj" prefetch={false} class="ring-2 ring-primary-500 flex font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
||||||
Get early access
|
Join our Discord
|
||||||
</Link>
|
</Link>
|
||||||
<div class="mt-6 flex w-full items-center justify-center gap-2 text-xs sm:text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
<div class="mt-6 flex w-full items-center justify-center gap-2 text-xs sm:text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
||||||
<span class="hover:text-primary-500 transition-colors duration-200">
|
<span class="hover:text-primary-500 transition-colors duration-200">
|
||||||
|
|||||||
@@ -521,8 +521,8 @@ export default component$(() => {
|
|||||||
</MotionComponent>
|
</MotionComponent>
|
||||||
<Footer client:load>
|
<Footer client:load>
|
||||||
<div class="w-full flex justify-center flex-col items-center gap-3">
|
<div class="w-full flex justify-center flex-col items-center gap-3">
|
||||||
<Link href="/auth/login" prefetch={false} class="flex font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
<Link href="https://discord.gg/6um5K6jrYj" prefetch={false} class="flex font-bricolage text-sm sm:text-base rounded-full bg-primary-500 px-5 py-4 font-semibold text-white transition-all hover:scale-105 active:scale-95 sm:px-6" >
|
||||||
Get early access
|
Join our Discord
|
||||||
</Link>
|
</Link>
|
||||||
<div class="mt-6 flex w-full items-center justify-center gap-2 text-xs sm:text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
<div class="mt-6 flex w-full items-center justify-center gap-2 text-xs sm:text-sm font-medium text-neutral-600 dark:text-neutral-400">
|
||||||
<span class="hover:text-primary-500 transition-colors duration-200">
|
<span class="hover:text-primary-500 transition-colors duration-200">
|
||||||
|
|||||||
12
containers/maitred.Containerfile
Normal file
12
containers/maitred.Containerfile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM docker.io/golang:1.24-bookworm AS go-build
|
||||||
|
WORKDIR /builder
|
||||||
|
COPY packages/maitred/ /builder/
|
||||||
|
RUN go build
|
||||||
|
|
||||||
|
FROM docker.io/golang:1.24-bookworm
|
||||||
|
COPY --from=go-build /builder/maitred /maitred/maitred
|
||||||
|
WORKDIR /maitred
|
||||||
|
|
||||||
|
RUN apt update && apt install -y --no-install-recommends pciutils
|
||||||
|
|
||||||
|
ENTRYPOINT ["/maitred/maitred"]
|
||||||
@@ -10,17 +10,17 @@ WORKDIR /relay
|
|||||||
# TODO: Switch running layer to just alpine (doesn't need golang dev stack)
|
# TODO: Switch running layer to just alpine (doesn't need golang dev stack)
|
||||||
|
|
||||||
# ENV flags
|
# ENV flags
|
||||||
|
ENV REGEN_IDENTITY=false
|
||||||
ENV VERBOSE=false
|
ENV VERBOSE=false
|
||||||
ENV DEBUG=false
|
ENV DEBUG=false
|
||||||
ENV ENDPOINT_PORT=8088
|
ENV ENDPOINT_PORT=8088
|
||||||
ENV WEBRTC_UDP_START=10000
|
ENV WEBRTC_UDP_START=0
|
||||||
ENV WEBRTC_UDP_END=20000
|
ENV WEBRTC_UDP_END=0
|
||||||
ENV STUN_SERVER="stun.l.google.com:19302"
|
ENV STUN_SERVER="stun.l.google.com:19302"
|
||||||
ENV WEBRTC_UDP_MUX=8088
|
ENV WEBRTC_UDP_MUX=8088
|
||||||
ENV WEBRTC_NAT_IPS=""
|
ENV WEBRTC_NAT_IPS=""
|
||||||
ENV AUTO_ADD_LOCAL_IP=true
|
ENV AUTO_ADD_LOCAL_IP=true
|
||||||
ENV TLS_CERT=""
|
ENV PERSIST_DIR="./persist-data"
|
||||||
ENV TLS_KEY=""
|
|
||||||
|
|
||||||
EXPOSE $ENDPOINT_PORT
|
EXPOSE $ENDPOINT_PORT
|
||||||
EXPOSE $WEBRTC_UDP_START-$WEBRTC_UDP_END/udp
|
EXPOSE $WEBRTC_UDP_START-$WEBRTC_UDP_END/udp
|
||||||
|
|||||||
@@ -85,8 +85,8 @@ RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
|||||||
pacman -Sy --noconfirm meson pkgconf cmake git gcc make \
|
pacman -Sy --noconfirm meson pkgconf cmake git gcc make \
|
||||||
libxkbcommon wayland gstreamer gst-plugins-base gst-plugins-good libinput
|
libxkbcommon wayland gstreamer gst-plugins-base gst-plugins-good libinput
|
||||||
|
|
||||||
# Clone repository with proper directory structure
|
# Clone repository
|
||||||
RUN git clone -b dev-dmabuf https://github.com/games-on-whales/gst-wayland-display.git
|
RUN git clone -b dev-dmabuf https://github.com/DatCaptainHorse/gst-wayland-display.git
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
#--------------------------------------------------------------------
|
||||||
FROM gst-wayland-deps AS gst-wayland-planner
|
FROM gst-wayland-deps AS gst-wayland-planner
|
||||||
@@ -132,9 +132,11 @@ RUN sed -i \
|
|||||||
# Core system components
|
# Core system components
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --needed --noconfirm \
|
pacman -Sy --needed --noconfirm \
|
||||||
vulkan-intel lib32-vulkan-intel vpl-gpu-rt mesa \
|
vulkan-intel lib32-vulkan-intel vpl-gpu-rt \
|
||||||
steam steam-native-runtime \
|
vulkan-radeon lib32-vulkan-radeon \
|
||||||
sudo xorg-xwayland seatd libinput labwc wlr-randr mangohud \
|
mesa \
|
||||||
|
steam steam-native-runtime gtk3 lib32-gtk3 \
|
||||||
|
sudo xorg-xwayland seatd libinput gamescope mangohud \
|
||||||
libssh2 curl wget \
|
libssh2 curl wget \
|
||||||
pipewire pipewire-pulse pipewire-alsa wireplumber \
|
pipewire pipewire-pulse pipewire-alsa wireplumber \
|
||||||
noto-fonts-cjk supervisor jq chwd lshw pacman-contrib && \
|
noto-fonts-cjk supervisor jq chwd lshw pacman-contrib && \
|
||||||
@@ -144,6 +146,9 @@ RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
|||||||
gst-plugins-bad gst-plugin-pipewire \
|
gst-plugins-bad gst-plugin-pipewire \
|
||||||
gst-plugin-webrtchttp gst-plugin-rswebrtc gst-plugin-rsrtp \
|
gst-plugin-webrtchttp gst-plugin-rswebrtc gst-plugin-rsrtp \
|
||||||
gst-plugin-va gst-plugin-qsv && \
|
gst-plugin-va gst-plugin-qsv && \
|
||||||
|
# lib32 GStreamer stack to fix some games with videos
|
||||||
|
pacman -Sy --needed --noconfirm \
|
||||||
|
lib32-gstreamer lib32-gst-plugins-base lib32-gst-plugins-good && \
|
||||||
# Cleanup
|
# Cleanup
|
||||||
paccache -rk1 && \
|
paccache -rk1 && \
|
||||||
rm -rf /usr/share/{info,man,doc}/*
|
rm -rf /usr/share/{info,man,doc}/*
|
||||||
@@ -163,8 +168,7 @@ ENV USER="nestri" \
|
|||||||
USER_PWD="nestri1234" \
|
USER_PWD="nestri1234" \
|
||||||
XDG_RUNTIME_DIR=/run/user/1000 \
|
XDG_RUNTIME_DIR=/run/user/1000 \
|
||||||
HOME=/home/nestri \
|
HOME=/home/nestri \
|
||||||
NVIDIA_DRIVER_CAPABILITIES=all \
|
NVIDIA_DRIVER_CAPABILITIES=all
|
||||||
NVIDIA_VISIBLE_DEVICES=all
|
|
||||||
|
|
||||||
RUN mkdir -p /home/${USER} && \
|
RUN mkdir -p /home/${USER} && \
|
||||||
groupadd -g ${GID} ${USER} && \
|
groupadd -g ${GID} ${USER} && \
|
||||||
@@ -185,6 +189,30 @@ RUN mkdir -p /run/dbus && \
|
|||||||
-e '/wants = \[/{s/hooks\.node\.suspend\s*//; s/,\s*\]/]/}' \
|
-e '/wants = \[/{s/hooks\.node\.suspend\s*//; s/,\s*\]/]/}' \
|
||||||
/usr/share/wireplumber/wireplumber.conf
|
/usr/share/wireplumber/wireplumber.conf
|
||||||
|
|
||||||
|
### PipeWire Latency Optimizations (1-5ms instead of 20ms) ###
|
||||||
|
RUN mkdir -p /etc/pipewire/pipewire.conf.d && \
|
||||||
|
echo "[audio]\
|
||||||
|
\n default.clock.rate = 48000\
|
||||||
|
\n default.clock.quantum = 128\
|
||||||
|
\n default.clock.min-quantum = 128\
|
||||||
|
\n default.clock.max-quantum = 256" > /etc/pipewire/pipewire.conf.d/low-latency.conf && \
|
||||||
|
mkdir -p /etc/wireplumber/main.lua.d && \
|
||||||
|
echo 'table.insert(default_nodes.rules, {\
|
||||||
|
\n matches = { { { "node.name", "matches", ".*" } } },\
|
||||||
|
\n apply_properties = {\
|
||||||
|
\n ["audio.format"] = "S16LE",\
|
||||||
|
\n ["audio.rate"] = 48000,\
|
||||||
|
\n ["audio.channels"] = 2,\
|
||||||
|
\n ["api.alsa.period-size"] = 128,\
|
||||||
|
\n ["api.alsa.headroom"] = 0,\
|
||||||
|
\n ["session.suspend-timeout-seconds"] = 0\
|
||||||
|
\n }\
|
||||||
|
\n})' > /etc/wireplumber/main.lua.d/50-low-latency.lua && \
|
||||||
|
echo "default-fragments = 2\
|
||||||
|
\ndefault-fragment-size-msec = 2" >> /etc/pulse/daemon.conf && \
|
||||||
|
echo "load-module module-loopback latency_msec=1" >> /etc/pipewire/pipewire.conf.d/loopback.conf
|
||||||
|
|
||||||
|
|
||||||
### Artifacts and Verification ###
|
### Artifacts and Verification ###
|
||||||
COPY --from=nestri-server-cached-builder /artifacts/nestri-server /usr/bin/
|
COPY --from=nestri-server-cached-builder /artifacts/nestri-server /usr/bin/
|
||||||
COPY --from=gst-wayland-cached-builder /artifacts/lib/ /usr/lib/
|
COPY --from=gst-wayland-cached-builder /artifacts/lib/ /usr/lib/
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#FIXME: A simple docker-compose file for running the MoQ relay and the cachyos server
|
|
||||||
160
infra/api.ts
160
infra/api.ts
@@ -1,82 +1,120 @@
|
|||||||
import { bus } from "./bus";
|
import { bus } from "./bus";
|
||||||
|
import { vpc } from "./vpc";
|
||||||
|
import { auth } from "./auth";
|
||||||
import { domain } from "./dns";
|
import { domain } from "./dns";
|
||||||
import { email } from "./email";
|
|
||||||
import { secret } from "./secret";
|
import { secret } from "./secret";
|
||||||
import { database } from "./database";
|
import { postgres } from "./postgres";
|
||||||
|
|
||||||
sst.Linkable.wrap(random.RandomString, (resource) => ({
|
const urls = new sst.Linkable("Urls", {
|
||||||
properties: {
|
properties: {
|
||||||
value: resource.result,
|
api: `https://api.${domain}`,
|
||||||
},
|
auth: `https://auth.${domain}`,
|
||||||
}));
|
site: $dev ? "http://localhost:3000" : `https://console.${domain}`,
|
||||||
|
}
|
||||||
export const urls = new sst.Linkable("Urls", {
|
|
||||||
properties: {
|
|
||||||
api: "https://api." + domain,
|
|
||||||
auth: "https://auth." + domain,
|
|
||||||
site: $dev ? "http://localhost:4321" : "https://" + domain,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const authFingerprintKey = new random.RandomString(
|
|
||||||
"AuthFingerprintKey",
|
|
||||||
{
|
|
||||||
length: 32,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const auth = new sst.aws.Auth("Auth", {
|
|
||||||
issuer: {
|
|
||||||
timeout: "3 minutes",
|
|
||||||
handler: "./packages/functions/src/auth.handler",
|
|
||||||
link: [
|
|
||||||
bus,
|
|
||||||
email,
|
|
||||||
database,
|
|
||||||
authFingerprintKey,
|
|
||||||
secret.PolarSecret,
|
|
||||||
secret.GithubClientID,
|
|
||||||
secret.DiscordClientID,
|
|
||||||
secret.GithubClientSecret,
|
|
||||||
secret.DiscordClientSecret,
|
|
||||||
],
|
|
||||||
permissions: [
|
|
||||||
{
|
|
||||||
actions: ["ses:SendEmail"],
|
|
||||||
resources: ["*"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
domain: {
|
|
||||||
name: "auth." + domain,
|
|
||||||
dns: sst.cloudflare.dns(),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const apiFunction = new sst.aws.Function("ApiFn", {
|
const apiFn = new sst.aws.Function("ApiFn", {
|
||||||
|
vpc,
|
||||||
handler: "packages/functions/src/api/index.handler",
|
handler: "packages/functions/src/api/index.handler",
|
||||||
|
streaming: !$dev,
|
||||||
link: [
|
link: [
|
||||||
bus,
|
bus,
|
||||||
urls,
|
urls,
|
||||||
database,
|
auth,
|
||||||
|
postgres,
|
||||||
|
secret.SteamApiKey,
|
||||||
secret.PolarSecret,
|
secret.PolarSecret,
|
||||||
|
secret.PolarWebhookSecret,
|
||||||
|
secret.NestriFamilyMonthly,
|
||||||
|
secret.NestriFamilyYearly,
|
||||||
|
secret.NestriFreeMonthly,
|
||||||
|
secret.NestriProMonthly,
|
||||||
|
secret.NestriProYearly,
|
||||||
],
|
],
|
||||||
timeout: "3 minutes",
|
url: true,
|
||||||
streaming: !$dev,
|
});
|
||||||
url: true
|
|
||||||
})
|
const provider = new aws.Provider("UsEast1", { region: "us-east-1" });
|
||||||
|
|
||||||
|
const webAcl = new aws.wafv2.WebAcl(
|
||||||
|
"ApiWaf",
|
||||||
|
{
|
||||||
|
scope: "CLOUDFRONT",
|
||||||
|
defaultAction: {
|
||||||
|
allow: {},
|
||||||
|
},
|
||||||
|
visibilityConfig: {
|
||||||
|
cloudwatchMetricsEnabled: true,
|
||||||
|
metricName: "api-rate-limit-metric",
|
||||||
|
sampledRequestsEnabled: true,
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
name: "rate-limit-rule",
|
||||||
|
priority: 1,
|
||||||
|
action: {
|
||||||
|
block: {
|
||||||
|
customResponse: {
|
||||||
|
responseCode: 429,
|
||||||
|
customResponseBodyKey: "rate-limit-response",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
statement: {
|
||||||
|
rateBasedStatement: {
|
||||||
|
limit: 2 * 60, // 2 rps per authorization header
|
||||||
|
evaluationWindowSec: 60,
|
||||||
|
aggregateKeyType: "CUSTOM_KEYS",
|
||||||
|
customKeys: [
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
name: "Authorization",
|
||||||
|
textTransformations: [{ priority: 0, type: "NONE" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visibilityConfig: {
|
||||||
|
cloudwatchMetricsEnabled: true,
|
||||||
|
metricName: "rate-limit-rule-metric",
|
||||||
|
sampledRequestsEnabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
customResponseBodies: [
|
||||||
|
{
|
||||||
|
key: "rate-limit-response",
|
||||||
|
content: JSON.stringify({
|
||||||
|
type: "rate_limit",
|
||||||
|
code: "too_many_requests",
|
||||||
|
message: "Rate limit exceeded. Please try again later.",
|
||||||
|
}),
|
||||||
|
contentType: "APPLICATION_JSON",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ provider },
|
||||||
|
);
|
||||||
|
|
||||||
export const api = new sst.aws.Router("Api", {
|
export const api = new sst.aws.Router("Api", {
|
||||||
routes: {
|
routes: {
|
||||||
"/*": apiFunction.url
|
"/*": apiFn.url,
|
||||||
},
|
},
|
||||||
domain: {
|
domain: {
|
||||||
name: "api." + domain,
|
name: "api." + domain,
|
||||||
dns: sst.cloudflare.dns(),
|
dns: sst.cloudflare.dns(),
|
||||||
},
|
},
|
||||||
})
|
transform: {
|
||||||
|
cdn(args) {
|
||||||
export const outputs = {
|
if (!args.transform) {
|
||||||
auth: auth.url,
|
args.transform = {
|
||||||
api: api.url,
|
distribution: {},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
args.transform!.distribution = {
|
||||||
|
webAclId: webAcl.arn,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
32
infra/auth.ts
Normal file
32
infra/auth.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { bus } from "./bus";
|
||||||
|
import { vpc } from "./vpc";
|
||||||
|
import { domain } from "./dns";
|
||||||
|
import { secret } from "./secret";
|
||||||
|
import { postgres } from "./postgres";
|
||||||
|
|
||||||
|
export const auth = new sst.aws.Auth("Auth", {
|
||||||
|
authorizer: {
|
||||||
|
vpc,
|
||||||
|
link: [
|
||||||
|
bus,
|
||||||
|
postgres,
|
||||||
|
secret.PolarSecret,
|
||||||
|
secret.GithubClientID,
|
||||||
|
secret.DiscordClientID,
|
||||||
|
secret.GithubClientSecret,
|
||||||
|
secret.DiscordClientSecret,
|
||||||
|
],
|
||||||
|
permissions: [
|
||||||
|
{
|
||||||
|
actions: ["ses:SendEmail"],
|
||||||
|
resources: ["*"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
handler: "packages/functions/src/auth/index.handler",
|
||||||
|
},
|
||||||
|
domain: {
|
||||||
|
name: "auth." + domain,
|
||||||
|
dns: sst.cloudflare.dns(),
|
||||||
|
},
|
||||||
|
forceUpgrade: "v2",
|
||||||
|
});
|
||||||
72
infra/bus.ts
72
infra/bus.ts
@@ -1,20 +1,70 @@
|
|||||||
import { email } from "./email";
|
import { vpc } from "./vpc";
|
||||||
import { allSecrets } from "./secret";
|
import { secret } from "./secret";
|
||||||
import { database } from "./database";
|
import { storage } from "./storage";
|
||||||
|
import { postgres } from "./postgres";
|
||||||
|
|
||||||
|
export const dlq = new sst.aws.Queue("Dlq");
|
||||||
|
|
||||||
|
export const retryQueue = new sst.aws.Queue("RetryQueue");
|
||||||
|
|
||||||
export const bus = new sst.aws.Bus("Bus");
|
export const bus = new sst.aws.Bus("Bus");
|
||||||
|
|
||||||
bus.subscribe("Event", {
|
export const eventSub = bus.subscribe("Event", {
|
||||||
handler: "./packages/functions/src/event/event.handler",
|
vpc,
|
||||||
|
handler: "packages/functions/src/events/index.handler",
|
||||||
link: [
|
link: [
|
||||||
database,
|
// email,
|
||||||
email,
|
bus,
|
||||||
...allSecrets],
|
storage,
|
||||||
timeout: "5 minutes",
|
postgres,
|
||||||
|
retryQueue,
|
||||||
|
secret.PolarSecret,
|
||||||
|
secret.SteamApiKey
|
||||||
|
],
|
||||||
|
environment: {
|
||||||
|
RETRIES: "2",
|
||||||
|
},
|
||||||
|
memory: "3002 MB",// For faster processing of large(r) images
|
||||||
|
timeout: "10 minutes",
|
||||||
|
});
|
||||||
|
|
||||||
|
new aws.lambda.FunctionEventInvokeConfig("EventConfig", {
|
||||||
|
functionName: $resolve([eventSub.nodes.function.name]).apply(
|
||||||
|
([name]) => name,
|
||||||
|
),
|
||||||
|
maximumRetryAttempts: 1,
|
||||||
|
destinationConfig: {
|
||||||
|
onFailure: {
|
||||||
|
destination: retryQueue.arn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
retryQueue.subscribe({
|
||||||
|
vpc,
|
||||||
|
handler: "packages/functions/src/queues/retry.handler",
|
||||||
|
timeout: "30 seconds",
|
||||||
|
environment: {
|
||||||
|
RETRIER_QUEUE_URL: retryQueue.url,
|
||||||
|
},
|
||||||
|
link: [
|
||||||
|
dlq,
|
||||||
|
retryQueue,
|
||||||
|
eventSub.nodes.function,
|
||||||
|
],
|
||||||
permissions: [
|
permissions: [
|
||||||
{
|
{
|
||||||
actions: ["ses:SendEmail"],
|
actions: ["lambda:GetFunction", "lambda:InvokeFunction"],
|
||||||
resources: ["*"],
|
resources: [
|
||||||
|
$interpolate`arn:aws:lambda:${aws.getRegionOutput().name}:${aws.getCallerIdentityOutput().accountId}:function:*`,
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
transform: {
|
||||||
|
function: {
|
||||||
|
deadLetterConfig: {
|
||||||
|
targetArn: dlq.arn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
18
infra/cdn.ts
Normal file
18
infra/cdn.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { domain } from "./dns";
|
||||||
|
import { storage } from "./storage";
|
||||||
|
|
||||||
|
export const cdn = new sst.aws.Router("CDNRouter", {
|
||||||
|
routes: {
|
||||||
|
"/*": {
|
||||||
|
bucket: storage,
|
||||||
|
rewrite: {
|
||||||
|
regex: "^/([a-zA-Z0-9_-]+)$",
|
||||||
|
to: "/public/$1"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
domain: {
|
||||||
|
name: "cdn." + domain,
|
||||||
|
dns: sst.cloudflare.dns()
|
||||||
|
}
|
||||||
|
});
|
||||||
6
infra/cluster.ts
Normal file
6
infra/cluster.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { vpc } from "./vpc";
|
||||||
|
|
||||||
|
export const cluster = new sst.aws.Cluster("Cluster", {
|
||||||
|
vpc,
|
||||||
|
forceUpgrade: "v2"
|
||||||
|
});
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//Created manually from the dashboard and shared with the whole team/org
|
|
||||||
const dbProject = neon.getProjectOutput({
|
|
||||||
id: "black-sky-26872933"
|
|
||||||
})
|
|
||||||
|
|
||||||
const dbBranchId = $app.stage !== "production" ?
|
|
||||||
new neon.Branch("NeonBranch", {
|
|
||||||
parentId: dbProject.defaultBranchId,
|
|
||||||
projectId: dbProject.id,
|
|
||||||
name: $app.stage,
|
|
||||||
}).id : dbProject.defaultBranchId
|
|
||||||
|
|
||||||
const dbEndpoint = new neon.Endpoint("NeonEndpoint", {
|
|
||||||
projectId: dbProject.id,
|
|
||||||
branchId: dbBranchId,
|
|
||||||
poolerEnabled: true,
|
|
||||||
type: "read_write",
|
|
||||||
})
|
|
||||||
|
|
||||||
const dbRole = new neon.Role("NeonRole", {
|
|
||||||
name: "admin",
|
|
||||||
branchId: dbBranchId,
|
|
||||||
projectId: dbProject.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
const db = new neon.Database("NeonDatabase", {
|
|
||||||
branchId: dbBranchId,
|
|
||||||
projectId: dbProject.id,
|
|
||||||
ownerName: dbRole.name,
|
|
||||||
name: `nestri-${$app.stage}`,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const database = new sst.Linkable("Database", {
|
|
||||||
properties: {
|
|
||||||
name: db.name,
|
|
||||||
user: dbRole.name,
|
|
||||||
host: dbEndpoint.host,
|
|
||||||
password: dbRole.password,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { domain } from "./dns";
|
import { domain } from "./dns";
|
||||||
|
|
||||||
export const email = new sst.aws.Email("Mail",{
|
export const email = new sst.aws.Email("Email",{
|
||||||
sender: domain,
|
sender: domain,
|
||||||
dns: sst.cloudflare.dns(),
|
dns: sst.cloudflare.dns(),
|
||||||
})
|
})
|
||||||
64
infra/postgres.ts
Normal file
64
infra/postgres.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { vpc } from "./vpc";
|
||||||
|
|
||||||
|
export const postgres = new sst.aws.Aurora("Database", {
|
||||||
|
vpc,
|
||||||
|
engine: "postgres",
|
||||||
|
scaling: {
|
||||||
|
min: "0 ACU",
|
||||||
|
max: "1 ACU",
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
clusterParameterGroup: {
|
||||||
|
parameters: [
|
||||||
|
{
|
||||||
|
name: "rds.logical_replication",
|
||||||
|
value: "1",
|
||||||
|
applyMethod: "pending-reboot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "max_slot_wal_keep_size",
|
||||||
|
value: "10240",
|
||||||
|
applyMethod: "pending-reboot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rds.force_ssl",
|
||||||
|
value: "0",
|
||||||
|
applyMethod: "pending-reboot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "max_connections",
|
||||||
|
value: "1000",
|
||||||
|
applyMethod: "pending-reboot",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
new sst.x.DevCommand("Studio", {
|
||||||
|
link: [postgres],
|
||||||
|
dev: {
|
||||||
|
command: "bun db:dev studio",
|
||||||
|
directory: "packages/core",
|
||||||
|
autostart: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// const migrator = new sst.aws.Function("DatabaseMigrator", {
|
||||||
|
// handler: "packages/functions/src/migrator.handler",
|
||||||
|
// link: [postgres],
|
||||||
|
// copyFiles: [
|
||||||
|
// {
|
||||||
|
// from: "packages/core/migrations",
|
||||||
|
// to: "./migrations",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (!$dev) {
|
||||||
|
// new aws.lambda.Invocation("DatabaseMigratorInvocation", {
|
||||||
|
// input: Date.now().toString(),
|
||||||
|
// functionName: migrator.name,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
9
infra/realtime.ts
Normal file
9
infra/realtime.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// import { auth } from "./auth";
|
||||||
|
import { postgres } from "./postgres";
|
||||||
|
|
||||||
|
export const device = new sst.aws.Realtime("Realtime", {
|
||||||
|
authorizer: {
|
||||||
|
link: [ postgres],
|
||||||
|
handler: "packages/functions/src/realtime/authorizer.handler"
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,11 +1,18 @@
|
|||||||
export const secret = {
|
export const secret = {
|
||||||
// InstantAppId: new sst.Secret("InstantAppId"),
|
|
||||||
PolarSecret: new sst.Secret("PolarSecret", process.env.POLAR_API_KEY),
|
PolarSecret: new sst.Secret("PolarSecret", process.env.POLAR_API_KEY),
|
||||||
|
SteamApiKey: new sst.Secret("SteamApiKey"),
|
||||||
GithubClientID: new sst.Secret("GithubClientID"),
|
GithubClientID: new sst.Secret("GithubClientID"),
|
||||||
DiscordClientID: new sst.Secret("DiscordClientID"),
|
DiscordClientID: new sst.Secret("DiscordClientID"),
|
||||||
|
PolarWebhookSecret: new sst.Secret("PolarWebhookSecret"),
|
||||||
GithubClientSecret: new sst.Secret("GithubClientSecret"),
|
GithubClientSecret: new sst.Secret("GithubClientSecret"),
|
||||||
// InstantAdminToken: new sst.Secret("InstantAdminToken"),
|
|
||||||
DiscordClientSecret: new sst.Secret("DiscordClientSecret"),
|
DiscordClientSecret: new sst.Secret("DiscordClientSecret"),
|
||||||
|
|
||||||
|
// Pricing
|
||||||
|
NestriFreeMonthly: new sst.Secret("NestriFreeMonthly"),
|
||||||
|
NestriProMonthly: new sst.Secret("NestriProMonthly"),
|
||||||
|
NestriProYearly: new sst.Secret("NestriProYearly"),
|
||||||
|
NestriFamilyMonthly: new sst.Secret("NestriFamilyMonthly"),
|
||||||
|
NestriFamilyYearly: new sst.Secret("NestriFamilyYearly"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const allSecrets = Object.values(secret);
|
export const allSecrets = Object.values(secret);
|
||||||
2
infra/stage.ts
Normal file
2
infra/stage.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const isPermanentStage =
|
||||||
|
$app.stage === "production" || $app.stage === "dev";
|
||||||
5
infra/storage.ts
Normal file
5
infra/storage.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const storage = new sst.aws.Bucket("Storage", {
|
||||||
|
access: "cloudfront"
|
||||||
|
});
|
||||||
|
|
||||||
|
export const zeroStorage = new sst.aws.Bucket("ZeroStorage");
|
||||||
11
infra/vpc.ts
Normal file
11
infra/vpc.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { isPermanentStage } from "./stage";
|
||||||
|
|
||||||
|
export const vpc = isPermanentStage
|
||||||
|
? new sst.aws.Vpc("VPC", {
|
||||||
|
az: 2,
|
||||||
|
// For lambdas to work in this VPC
|
||||||
|
nat: "ec2",
|
||||||
|
// For SST tunnel to work
|
||||||
|
bastion: true,
|
||||||
|
})
|
||||||
|
: sst.aws.Vpc.get("VPC", "vpc-0beb1cdc21a725748");
|
||||||
11
infra/www.ts
11
infra/www.ts
@@ -1,9 +1,12 @@
|
|||||||
// This is the website part where people play and connect
|
// This is the website part where people play and connect
|
||||||
|
import { api } from "./api";
|
||||||
|
import { cdn } from "./cdn";
|
||||||
|
import { auth } from "./auth";
|
||||||
|
import { zero } from "./zero";
|
||||||
import { domain } from "./dns";
|
import { domain } from "./dns";
|
||||||
import { auth, api } from "./api";
|
|
||||||
|
|
||||||
new sst.aws.StaticSite("Web", {
|
new sst.aws.StaticSite("Web", {
|
||||||
path: "./packages/www",
|
path: "packages/www",
|
||||||
build: {
|
build: {
|
||||||
output: "./dist",
|
output: "./dist",
|
||||||
command: "bun run build",
|
command: "bun run build",
|
||||||
@@ -14,7 +17,9 @@ new sst.aws.StaticSite("Web", {
|
|||||||
},
|
},
|
||||||
environment: {
|
environment: {
|
||||||
VITE_API_URL: api.url,
|
VITE_API_URL: api.url,
|
||||||
VITE_AUTH_URL: auth.url,
|
VITE_CDN_URL: cdn.url,
|
||||||
VITE_STAGE: $app.stage,
|
VITE_STAGE: $app.stage,
|
||||||
|
VITE_AUTH_URL: auth.url,
|
||||||
|
VITE_ZERO_URL: zero.url,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
186
infra/zero.ts
Normal file
186
infra/zero.ts
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
import { auth } from "./auth";
|
||||||
|
import { domain } from "./dns";
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { cluster } from "./cluster";
|
||||||
|
import { postgres } from "./postgres";
|
||||||
|
import { zeroStorage } from "./storage";
|
||||||
|
|
||||||
|
const connectionString = $interpolate`postgresql://${postgres.username}:${postgres.password}@${postgres.host}:${postgres.port}/${postgres.database}`;
|
||||||
|
|
||||||
|
const tag = $dev
|
||||||
|
? `latest`
|
||||||
|
: JSON.parse(
|
||||||
|
readFileSync("./node_modules/@rocicorp/zero/package.json").toString(),
|
||||||
|
).version.replace("+", "-");
|
||||||
|
|
||||||
|
const zeroEnv = {
|
||||||
|
FORCE: "1",
|
||||||
|
NO_COLOR: "1",
|
||||||
|
ZERO_LOG_LEVEL: "info",
|
||||||
|
ZERO_LITESTREAM_LOG_LEVEL: "info",
|
||||||
|
ZERO_UPSTREAM_DB: connectionString,
|
||||||
|
ZERO_IMAGE_URL: `rocicorp/zero:${tag}`,
|
||||||
|
ZERO_CVR_DB: connectionString,
|
||||||
|
ZERO_CHANGE_DB: connectionString,
|
||||||
|
ZERO_REPLICA_FILE: "/tmp/nestri.db",
|
||||||
|
ZERO_LITESTREAM_RESTORE_PARALLELISM: "64",
|
||||||
|
ZERO_APP_ID: $app.stage,
|
||||||
|
ZERO_AUTH_JWKS_URL: $interpolate`${auth.url}/.well-known/jwks.json`,
|
||||||
|
ZERO_INITIAL_SYNC_ROW_BATCH_SIZE: "30000",
|
||||||
|
NODE_OPTIONS: "--max-old-space-size=8192",
|
||||||
|
...($dev
|
||||||
|
? {
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
ZERO_LITESTREAM_BACKUP_URL: $interpolate`s3://${zeroStorage.name}/zero/0`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Replication Manager Service
|
||||||
|
const replicationManager = !$dev
|
||||||
|
? new sst.aws.Service(`ZeroReplication`, {
|
||||||
|
cluster,
|
||||||
|
wait: true,
|
||||||
|
cpu: "0.5 vCPU",
|
||||||
|
memory: "1 GB",
|
||||||
|
capacity: "spot",
|
||||||
|
architecture: "arm64",
|
||||||
|
image: zeroEnv.ZERO_IMAGE_URL,
|
||||||
|
link: [zeroStorage, postgres],
|
||||||
|
health: {
|
||||||
|
command: ["CMD-SHELL", "curl -f http://localhost:4849/ || exit 1"],
|
||||||
|
interval: "5 seconds",
|
||||||
|
retries: 3,
|
||||||
|
startPeriod: "300 seconds",
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
...zeroEnv,
|
||||||
|
ZERO_CHANGE_MAX_CONNS: "3",
|
||||||
|
ZERO_NUM_SYNC_WORKERS: "0",
|
||||||
|
},
|
||||||
|
logging: {
|
||||||
|
retention: "1 month",
|
||||||
|
},
|
||||||
|
loadBalancer: {
|
||||||
|
public: false,
|
||||||
|
ports: [
|
||||||
|
{
|
||||||
|
listen: "80/http",
|
||||||
|
forward: "4849/http",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
loadBalancer: {
|
||||||
|
idleTimeout: 3600,
|
||||||
|
},
|
||||||
|
service: {
|
||||||
|
healthCheckGracePeriodSeconds: 900,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}) : undefined;
|
||||||
|
|
||||||
|
// Permissions deployment
|
||||||
|
// const permissions = new sst.aws.Function(
|
||||||
|
// "ZeroPermissions",
|
||||||
|
// {
|
||||||
|
// vpc,
|
||||||
|
// link: [postgres],
|
||||||
|
// handler: "packages/functions/src/zero.handler",
|
||||||
|
// // environment: { ["ZERO_UPSTREAM_DB"]: connectionString },
|
||||||
|
// copyFiles: [{
|
||||||
|
// from: "packages/zero/permissions.sql",
|
||||||
|
// to: "./.permissions.sql"
|
||||||
|
// }],
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (replicationManager) {
|
||||||
|
// new aws.lambda.Invocation(
|
||||||
|
// "ZeroPermissionsInvocation",
|
||||||
|
// {
|
||||||
|
// input: Date.now().toString(),
|
||||||
|
// functionName: permissions.name,
|
||||||
|
// },
|
||||||
|
// { dependsOn: replicationManager }
|
||||||
|
// );
|
||||||
|
// // new command.local.Command(
|
||||||
|
// // "ZeroPermission",
|
||||||
|
// // {
|
||||||
|
// // dir: process.cwd() + "/packages/zero",
|
||||||
|
// // environment: {
|
||||||
|
// // ZERO_UPSTREAM_DB: connectionString,
|
||||||
|
// // },
|
||||||
|
// // create: "bun run zero-deploy-permissions",
|
||||||
|
// // triggers: [Date.now()],
|
||||||
|
// // },
|
||||||
|
// // {
|
||||||
|
// // dependsOn: [replicationManager],
|
||||||
|
// // },
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
|
||||||
|
export const zero = new sst.aws.Service("Zero", {
|
||||||
|
cluster,
|
||||||
|
image: zeroEnv.ZERO_IMAGE_URL,
|
||||||
|
link: [zeroStorage, postgres],
|
||||||
|
architecture: "arm64",
|
||||||
|
cpu: "0.5 vCPU",
|
||||||
|
memory: "1 GB",
|
||||||
|
capacity: "spot",
|
||||||
|
environment: {
|
||||||
|
...zeroEnv,
|
||||||
|
...($dev
|
||||||
|
? {
|
||||||
|
ZERO_NUM_SYNC_WORKERS: "1",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
ZERO_CHANGE_STREAMER_URI: replicationManager.url.apply((val) =>
|
||||||
|
val.replace("http://", "ws://"),
|
||||||
|
),
|
||||||
|
ZERO_UPSTREAM_MAX_CONNS: "15",
|
||||||
|
ZERO_CVR_MAX_CONNS: "160",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
health: {
|
||||||
|
retries: 3,
|
||||||
|
command: ["CMD-SHELL", "curl -f http://localhost:4848/ || exit 1"],
|
||||||
|
interval: "5 seconds",
|
||||||
|
startPeriod: "300 seconds",
|
||||||
|
},
|
||||||
|
loadBalancer: {
|
||||||
|
domain: {
|
||||||
|
name: "zero." + domain,
|
||||||
|
dns: sst.cloudflare.dns()
|
||||||
|
},
|
||||||
|
rules: [
|
||||||
|
{ listen: "443/https", forward: "4848/http" },
|
||||||
|
{ listen: "80/http", forward: "4848/http" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
scaling: {
|
||||||
|
min: 1,
|
||||||
|
max: 4,
|
||||||
|
},
|
||||||
|
logging: {
|
||||||
|
retention: "1 month",
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
service: {
|
||||||
|
healthCheckGracePeriodSeconds: 900,
|
||||||
|
},
|
||||||
|
// taskDefinition: {
|
||||||
|
// ephemeralStorage: {
|
||||||
|
// sizeInGib: 200,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
loadBalancer: {
|
||||||
|
idleTimeout: 3600,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dev: {
|
||||||
|
command: "bun dev",
|
||||||
|
directory: "packages/zero",
|
||||||
|
url: "http://localhost:4848",
|
||||||
|
},
|
||||||
|
});
|
||||||
13
package.json
13
package.json
@@ -3,6 +3,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@cloudflare/workers-types": "4.20240821.1",
|
"@cloudflare/workers-types": "4.20240821.1",
|
||||||
"@pulumi/pulumi": "^3.134.0",
|
"@pulumi/pulumi": "^3.134.0",
|
||||||
|
"@tsconfig/node22": "^22.0.1",
|
||||||
"@types/aws-lambda": "8.10.147",
|
"@types/aws-lambda": "8.10.147",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.4.5"
|
||||||
@@ -16,9 +17,19 @@
|
|||||||
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
||||||
"sso": "aws sso login --sso-session=nestri --no-browser --use-device-code"
|
"sso": "aws sso login --sso-session=nestri --no-browser --use-device-code"
|
||||||
},
|
},
|
||||||
|
"overrides": {
|
||||||
|
"@openauthjs/openauth": "0.4.3",
|
||||||
|
"steam-session": "1.9.3"
|
||||||
|
},
|
||||||
|
"patchedDependencies": {
|
||||||
|
"@macaron-css/solid@1.5.3": "patches/@macaron-css%2Fsolid@1.5.3.patch",
|
||||||
|
"drizzle-orm@0.36.1": "patches/drizzle-orm@0.36.1.patch",
|
||||||
|
"steam-session@1.9.3": "patches/steam-session@1.9.3.patch"
|
||||||
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"core-js-pure",
|
"core-js-pure",
|
||||||
"esbuild",
|
"esbuild",
|
||||||
|
"protobufjs",
|
||||||
"workerd"
|
"workerd"
|
||||||
],
|
],
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
@@ -26,6 +37,6 @@
|
|||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"sst": "3.9.1"
|
"sst": "^3.11.21"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
import { Resource } from "sst";
|
import { Resource } from "sst";
|
||||||
import { defineConfig } from "drizzle-kit";
|
import { defineConfig } from "drizzle-kit";
|
||||||
|
|
||||||
function addPoolerSuffix(original: string): string {
|
const connection = {
|
||||||
const firstDotIndex = original.indexOf('.');
|
user: Resource.Database.username,
|
||||||
if (firstDotIndex === -1) return original + '-pooler';
|
password: Resource.Database.password,
|
||||||
return original.slice(0, firstDotIndex) + '-pooler' + original.slice(firstDotIndex);
|
host: Resource.Database.host,
|
||||||
}
|
};
|
||||||
|
|
||||||
const dbHost = addPoolerSuffix(Resource.Database.host)
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
schema: "./src/**/*.sql.ts",
|
verbose: true,
|
||||||
|
strict: true,
|
||||||
out: "./migrations",
|
out: "./migrations",
|
||||||
dialect: "postgresql",
|
dialect: "postgresql",
|
||||||
verbose: true,
|
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
url: `postgresql://${Resource.Database.user}:${Resource.Database.password}@${dbHost}/${Resource.Database.name}?sslmode=require`,
|
url: `postgres://${connection.user}:${connection.password}@${connection.host}/nestri`,
|
||||||
},
|
},
|
||||||
|
schema: "./src/**/*.sql.ts",
|
||||||
});
|
});
|
||||||
@@ -14,8 +14,9 @@ CREATE TABLE "team" (
|
|||||||
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"time_deleted" timestamp with time zone,
|
"time_deleted" timestamp with time zone,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
"slug" varchar(255) NOT NULL,
|
"slug" varchar(255) NOT NULL,
|
||||||
"name" varchar(255) NOT NULL
|
"plan_type" text NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE "user" (
|
CREATE TABLE "user" (
|
||||||
@@ -24,14 +25,15 @@ CREATE TABLE "user" (
|
|||||||
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
"time_deleted" timestamp with time zone,
|
"time_deleted" timestamp with time zone,
|
||||||
"avatar_url" text,
|
"avatar_url" text,
|
||||||
"email" varchar(255) NOT NULL,
|
|
||||||
"name" varchar(255) NOT NULL,
|
"name" varchar(255) NOT NULL,
|
||||||
"discriminator" integer NOT NULL,
|
"discriminator" integer NOT NULL,
|
||||||
"polar_customer_id" varchar(255) NOT NULL,
|
"email" varchar(255) NOT NULL,
|
||||||
|
"polar_customer_id" varchar(255),
|
||||||
|
"flags" json DEFAULT '{}'::json,
|
||||||
CONSTRAINT "user_polar_customer_id_unique" UNIQUE("polar_customer_id")
|
CONSTRAINT "user_polar_customer_id_unique" UNIQUE("polar_customer_id")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX "member_email" ON "member" USING btree ("team_id","email");--> statement-breakpoint
|
|
||||||
CREATE INDEX "email_global" ON "member" USING btree ("email");--> statement-breakpoint
|
CREATE INDEX "email_global" ON "member" USING btree ("email");--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX "slug" ON "team" USING btree ("slug");--> statement-breakpoint
|
CREATE UNIQUE INDEX "member_email" ON "member" USING btree ("team_id","email");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "team_slug" ON "team" USING btree ("slug");--> statement-breakpoint
|
||||||
CREATE UNIQUE INDEX "user_email" ON "user" USING btree ("email");
|
CREATE UNIQUE INDEX "user_email" ON "user" USING btree ("email");
|
||||||
@@ -1 +0,0 @@
|
|||||||
ALTER TABLE "user" ALTER COLUMN "polar_customer_id" DROP NOT NULL;
|
|
||||||
2
packages/core/migrations/0001_nifty_sauron.sql
Normal file
2
packages/core/migrations/0001_nifty_sauron.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DROP INDEX "team_slug";--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "slug" ON "team" USING btree ("slug");
|
||||||
17
packages/core/migrations/0002_simple_outlaw_kid.sql
Normal file
17
packages/core/migrations/0002_simple_outlaw_kid.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
CREATE TABLE "steam" (
|
||||||
|
"id" char(30) NOT NULL,
|
||||||
|
"user_id" char(30) NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"avatar_url" text NOT NULL,
|
||||||
|
"access_token" text NOT NULL,
|
||||||
|
"email" varchar(255) NOT NULL,
|
||||||
|
"country" varchar(255) NOT NULL,
|
||||||
|
"username" varchar(255) NOT NULL,
|
||||||
|
"persona_name" varchar(255) NOT NULL,
|
||||||
|
CONSTRAINT "steam_user_id_id_pk" PRIMARY KEY("user_id","id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE INDEX "global_steam_email" ON "steam" USING btree ("email");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "steam_email" ON "steam" USING btree ("user_id","email");
|
||||||
13
packages/core/migrations/0002_tiny_toad_men.sql
Normal file
13
packages/core/migrations/0002_tiny_toad_men.sql
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
CREATE TABLE "machine" (
|
||||||
|
"id" char(30) PRIMARY KEY NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"country" text NOT NULL,
|
||||||
|
"timezone" text NOT NULL,
|
||||||
|
"location" "point" NOT NULL,
|
||||||
|
"fingerprint" varchar(32) NOT NULL,
|
||||||
|
"country_code" varchar(2) NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "machine_fingerprint" ON "machine" USING btree ("fingerprint");
|
||||||
22
packages/core/migrations/0003_first_big_bertha.sql
Normal file
22
packages/core/migrations/0003_first_big_bertha.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
CREATE TABLE "machine" (
|
||||||
|
"id" char(30) PRIMARY KEY NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"country" text NOT NULL,
|
||||||
|
"timezone" text NOT NULL,
|
||||||
|
"location" "point" NOT NULL,
|
||||||
|
"fingerprint" varchar(32) NOT NULL,
|
||||||
|
"country_code" varchar(2) NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" RENAME COLUMN "country" TO "country_code";--> statement-breakpoint
|
||||||
|
DROP INDEX "global_steam_email";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD COLUMN "time_seen" timestamp with time zone;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD COLUMN "steam_id" integer NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD COLUMN "last_game" json NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD COLUMN "steam_email" varchar(255) NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD COLUMN "limitation" json NOT NULL;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "machine_fingerprint" ON "machine" USING btree ("fingerprint");--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" DROP COLUMN "access_token";--> statement-breakpoint
|
||||||
|
ALTER TABLE "user" DROP COLUMN "flags";
|
||||||
8
packages/core/migrations/0004_amused_mattie_franklin.sql
Normal file
8
packages/core/migrations/0004_amused_mattie_franklin.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
ALTER TABLE "steam" RENAME COLUMN "time_seen" TO "last_seen";--> statement-breakpoint
|
||||||
|
DROP INDEX "steam_email";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" DROP CONSTRAINT "steam_user_id_id_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD PRIMARY KEY ("id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "machine" ADD CONSTRAINT "machine_user_id_id_pk" PRIMARY KEY("user_id","id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "machine" ADD COLUMN "user_id" char(30);--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" ADD CONSTRAINT "steam_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam" DROP COLUMN "email";
|
||||||
2
packages/core/migrations/0005_aspiring_stature.sql
Normal file
2
packages/core/migrations/0005_aspiring_stature.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "machine" DROP CONSTRAINT "machine_user_id_id_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "machine" DROP COLUMN "user_id";
|
||||||
2
packages/core/migrations/0006_worthless_dreadnoughts.sql
Normal file
2
packages/core/migrations/0006_worthless_dreadnoughts.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "member" ADD COLUMN "role" text NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "team" DROP COLUMN "plan_type";
|
||||||
15
packages/core/migrations/0007_warm_secret_warriors.sql
Normal file
15
packages/core/migrations/0007_warm_secret_warriors.sql
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
CREATE TABLE "subscription" (
|
||||||
|
"id" char(30) NOT NULL,
|
||||||
|
"user_id" char(30) NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"team_id" char(30) NOT NULL,
|
||||||
|
"standing" text NOT NULL,
|
||||||
|
"plan_type" text NOT NULL,
|
||||||
|
"tokens" integer NOT NULL,
|
||||||
|
"product_id" varchar(255),
|
||||||
|
"subscription_id" varchar(255)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "subscription" ADD CONSTRAINT "subscription_team_id_team_id_fk" FOREIGN KEY ("team_id") REFERENCES "public"."team"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
3
packages/core/migrations/0008_third_mindworm.sql
Normal file
3
packages/core/migrations/0008_third_mindworm.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE "subscription" ADD CONSTRAINT "subscription_id_team_id_pk" PRIMARY KEY("id","team_id");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "subscription_id" ON "subscription" USING btree ("id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "subscription_user_id" ON "subscription" USING btree ("user_id");
|
||||||
2
packages/core/migrations/0009_luxuriant_wraith.sql
Normal file
2
packages/core/migrations/0009_luxuriant_wraith.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE UNIQUE INDEX "steam_id" ON "steam" USING btree ("steam_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "steam_user_id" ON "steam" USING btree ("user_id");
|
||||||
94
packages/core/migrations/0010_certain_dust.sql
Normal file
94
packages/core/migrations/0010_certain_dust.sql
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
CREATE TYPE "public"."member_role" AS ENUM('child', 'adult');--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."steam_status" AS ENUM('online', 'offline', 'dnd', 'playing');--> statement-breakpoint
|
||||||
|
CREATE TABLE "steam_account_credentials" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"steam_id" varchar(255) PRIMARY KEY NOT NULL,
|
||||||
|
"refresh_token" text NOT NULL,
|
||||||
|
"expiry" timestamp with time zone NOT NULL,
|
||||||
|
"username" varchar(255) NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "friends_list" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"steam_id" varchar(255) NOT NULL,
|
||||||
|
"friend_steam_id" varchar(255) NOT NULL,
|
||||||
|
CONSTRAINT "friends_list_steam_id_friend_steam_id_pk" PRIMARY KEY("steam_id","friend_steam_id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "members" (
|
||||||
|
"id" char(30) NOT NULL,
|
||||||
|
"team_id" char(30) NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"user_id" char(30),
|
||||||
|
"steam_id" varchar(255) NOT NULL,
|
||||||
|
"role" "member_role" NOT NULL,
|
||||||
|
CONSTRAINT "members_id_team_id_pk" PRIMARY KEY("id","team_id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "steam_accounts" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"steam_id" varchar(255) PRIMARY KEY NOT NULL,
|
||||||
|
"user_id" char(30),
|
||||||
|
"status" "steam_status" NOT NULL,
|
||||||
|
"last_synced_at" timestamp with time zone NOT NULL,
|
||||||
|
"real_name" varchar(255),
|
||||||
|
"member_since" timestamp with time zone NOT NULL,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
|
"profile_url" varchar(255),
|
||||||
|
"username" varchar(255) NOT NULL,
|
||||||
|
"avatar_hash" varchar(255) NOT NULL,
|
||||||
|
"limitations" json NOT NULL,
|
||||||
|
CONSTRAINT "idx_steam_username" UNIQUE("username")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "teams" (
|
||||||
|
"id" char(30) PRIMARY KEY NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
|
"owner_id" char(30) NOT NULL,
|
||||||
|
"invite_code" varchar(10) NOT NULL,
|
||||||
|
"slug" varchar(255) NOT NULL,
|
||||||
|
"max_members" bigint NOT NULL,
|
||||||
|
CONSTRAINT "idx_team_invite_code" UNIQUE("invite_code")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "users" (
|
||||||
|
"id" char(30) PRIMARY KEY NOT NULL,
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"email" varchar(255) NOT NULL,
|
||||||
|
"avatar_url" text,
|
||||||
|
"last_login" timestamp with time zone NOT NULL,
|
||||||
|
"name" varchar(255) NOT NULL,
|
||||||
|
"polar_customer_id" varchar(255),
|
||||||
|
CONSTRAINT "idx_user_email" UNIQUE("email")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
DROP TABLE "machine" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "member" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "steam" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "subscription" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "team" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "user" CASCADE;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_account_credentials" ADD CONSTRAINT "steam_account_credentials_steam_id_steam_accounts_steam_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("steam_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" ADD CONSTRAINT "friends_list_steam_id_steam_accounts_steam_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("steam_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" ADD CONSTRAINT "friends_list_friend_steam_id_steam_accounts_steam_id_fk" FOREIGN KEY ("friend_steam_id") REFERENCES "public"."steam_accounts"("steam_id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "members" ADD CONSTRAINT "members_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "members" ADD CONSTRAINT "members_steam_id_steam_accounts_steam_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("steam_id") ON DELETE cascade ON UPDATE restrict;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_accounts" ADD CONSTRAINT "steam_accounts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" ADD CONSTRAINT "teams_owner_id_users_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" ADD CONSTRAINT "teams_slug_steam_accounts_username_fk" FOREIGN KEY ("slug") REFERENCES "public"."steam_accounts"("username") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "idx_member_steam_id" ON "members" USING btree ("team_id","steam_id");--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "idx_member_user_id" ON "members" USING btree ("team_id","user_id") WHERE "members"."user_id" is not null;--> statement-breakpoint
|
||||||
|
CREATE UNIQUE INDEX "idx_team_slug" ON "teams" USING btree ("slug");
|
||||||
89
packages/core/migrations/0011_simple_azazel.sql
Normal file
89
packages/core/migrations/0011_simple_azazel.sql
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
CREATE TYPE "public"."compatibility" AS ENUM('high', 'mid', 'low', 'unknown');--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."category_type" AS ENUM('tag', 'genre', 'publisher', 'developer');--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."image_type" AS ENUM('heroArt', 'icon', 'logo', 'superHeroArt', 'poster', 'boxArt', 'screenshot', 'background');--> statement-breakpoint
|
||||||
|
CREATE TABLE "base_games" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"id" varchar(255) PRIMARY KEY NOT NULL,
|
||||||
|
"slug" varchar(255) NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"release_date" timestamp with time zone NOT NULL,
|
||||||
|
"size" json NOT NULL,
|
||||||
|
"description" text NOT NULL,
|
||||||
|
"primary_genre" text NOT NULL,
|
||||||
|
"controller_support" text,
|
||||||
|
"compatibility" "compatibility" DEFAULT 'unknown' NOT NULL,
|
||||||
|
"score" numeric(2, 1) NOT NULL,
|
||||||
|
CONSTRAINT "idx_base_games_slug" UNIQUE("slug")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "categories" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"slug" varchar(255) NOT NULL,
|
||||||
|
"type" "category_type" NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
CONSTRAINT "categories_slug_type_pk" PRIMARY KEY("slug","type")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "games" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"base_game_id" varchar(255) NOT NULL,
|
||||||
|
"category_slug" varchar(255) NOT NULL,
|
||||||
|
"type" "category_type" NOT NULL,
|
||||||
|
CONSTRAINT "games_base_game_id_category_slug_type_pk" PRIMARY KEY("base_game_id","category_slug","type")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "images" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"type" "image_type" NOT NULL,
|
||||||
|
"image_hash" varchar(255) NOT NULL,
|
||||||
|
"base_game_id" varchar(255) NOT NULL,
|
||||||
|
"source_url" text NOT NULL,
|
||||||
|
"position" integer DEFAULT 0 NOT NULL,
|
||||||
|
"file_size" integer NOT NULL,
|
||||||
|
"dimensions" json NOT NULL,
|
||||||
|
"extracted_color" json NOT NULL,
|
||||||
|
CONSTRAINT "images_image_hash_type_base_game_id_position_pk" PRIMARY KEY("image_hash","type","base_game_id","position")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE "game_libraries" (
|
||||||
|
"time_created" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_updated" timestamp with time zone DEFAULT now() NOT NULL,
|
||||||
|
"time_deleted" timestamp with time zone,
|
||||||
|
"base_game_id" varchar(255) NOT NULL,
|
||||||
|
"owner_id" varchar(255) NOT NULL,
|
||||||
|
CONSTRAINT "game_libraries_base_game_id_owner_id_pk" PRIMARY KEY("base_game_id","owner_id")
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_accounts" RENAME COLUMN "steam_id" TO "id";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_account_credentials" DROP CONSTRAINT "steam_account_credentials_steam_id_steam_accounts_steam_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" DROP CONSTRAINT "friends_list_steam_id_steam_accounts_steam_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" DROP CONSTRAINT "friends_list_friend_steam_id_steam_accounts_steam_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "members" DROP CONSTRAINT "members_steam_id_steam_accounts_steam_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "games" ADD CONSTRAINT "games_base_game_id_base_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "public"."base_games"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "games" ADD CONSTRAINT "games_categories_fkey" FOREIGN KEY ("category_slug","type") REFERENCES "public"."categories"("slug","type") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "images" ADD CONSTRAINT "images_base_game_id_base_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "public"."base_games"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD CONSTRAINT "game_libraries_base_game_id_base_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "public"."base_games"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD CONSTRAINT "game_libraries_owner_id_steam_accounts_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_categories_type" ON "categories" USING btree ("type");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_games_category_slug" ON "games" USING btree ("category_slug");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_games_category_type" ON "games" USING btree ("type");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_images_type" ON "images" USING btree ("type");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_images_game_id" ON "images" USING btree ("base_game_id");--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_game_libraries_owner_id" ON "game_libraries" USING btree ("owner_id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_account_credentials" ADD CONSTRAINT "steam_account_credentials_steam_id_steam_accounts_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" ADD CONSTRAINT "friends_list_steam_id_steam_accounts_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "friends_list" ADD CONSTRAINT "friends_list_friend_steam_id_steam_accounts_id_fk" FOREIGN KEY ("friend_steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "members" ADD CONSTRAINT "members_steam_id_steam_accounts_id_fk" FOREIGN KEY ("steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE restrict;--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_friends_list_friend_steam_id" ON "friends_list" USING btree ("friend_steam_id");
|
||||||
4
packages/core/migrations/0012_glorious_jetstream.sql
Normal file
4
packages/core/migrations/0012_glorious_jetstream.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE "games" DROP CONSTRAINT "games_categories_fkey";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "games" ADD CONSTRAINT "games_categories_fkey" FOREIGN KEY ("category_slug","type") REFERENCES "public"."categories"("slug","type") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_games_category_slug_type" ON "games" USING btree ("category_slug","type");
|
||||||
3
packages/core/migrations/0013_neat_colleen_wing.sql
Normal file
3
packages/core/migrations/0013_neat_colleen_wing.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
CREATE TYPE "public"."controller_support" AS ENUM('full', 'unknown');--> statement-breakpoint
|
||||||
|
ALTER TABLE "base_games" ALTER COLUMN "controller_support" SET DATA TYPE controller_support;--> statement-breakpoint
|
||||||
|
ALTER TABLE "base_games" ALTER COLUMN "controller_support" SET NOT NULL;
|
||||||
1
packages/core/migrations/0014_thin_groot.sql
Normal file
1
packages/core/migrations/0014_thin_groot.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "base_games" ALTER COLUMN "primary_genre" DROP NOT NULL;
|
||||||
1
packages/core/migrations/0015_handy_giant_man.sql
Normal file
1
packages/core/migrations/0015_handy_giant_man.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE "public"."controller_support" ADD VALUE 'partial' BEFORE 'unknown';
|
||||||
4
packages/core/migrations/0016_melted_johnny_storm.sql
Normal file
4
packages/core/migrations/0016_melted_johnny_storm.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE "game_libraries" ADD COLUMN "time_acquired" timestamp with time zone NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD COLUMN "last_played" timestamp with time zone NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD COLUMN "total_playtime" integer NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD COLUMN "is_family_shared" boolean NOT NULL;
|
||||||
4
packages/core/migrations/0017_zippy_nico_minoru.sql
Normal file
4
packages/core/migrations/0017_zippy_nico_minoru.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE "public"."images" ALTER COLUMN "type" SET DATA TYPE text;--> statement-breakpoint
|
||||||
|
DROP TYPE "public"."image_type";--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."image_type" AS ENUM('heroArt', 'icon', 'logo', 'superHeroArt', 'poster', 'boxArt', 'screenshot', 'backdrop');--> statement-breakpoint
|
||||||
|
ALTER TABLE "public"."images" ALTER COLUMN "type" SET DATA TYPE "public"."image_type" USING "type"::"public"."image_type";
|
||||||
4
packages/core/migrations/0018_solid_enchantress.sql
Normal file
4
packages/core/migrations/0018_solid_enchantress.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE "public"."images" ALTER COLUMN "type" SET DATA TYPE text;--> statement-breakpoint
|
||||||
|
DROP TYPE "public"."image_type";--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."image_type" AS ENUM('heroArt', 'icon', 'logo', 'banner', 'poster', 'boxArt', 'screenshot', 'backdrop');--> statement-breakpoint
|
||||||
|
ALTER TABLE "public"."images" ALTER COLUMN "type" SET DATA TYPE "public"."image_type" USING "type"::"public"."image_type";
|
||||||
19
packages/core/migrations/0019_charming_namorita.sql
Normal file
19
packages/core/migrations/0019_charming_namorita.sql
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
Unfortunately in current drizzle-kit version we can't automatically get name for primary key.
|
||||||
|
We are working on making it available!
|
||||||
|
|
||||||
|
Meanwhile you can:
|
||||||
|
1. Check pk name in your database, by running
|
||||||
|
SELECT constraint_name FROM information_schema.table_constraints
|
||||||
|
WHERE table_schema = 'public'
|
||||||
|
AND table_name = 'steam_account_credentials'
|
||||||
|
AND constraint_type = 'PRIMARY KEY';
|
||||||
|
2. Uncomment code below and paste pk name manually
|
||||||
|
|
||||||
|
Hope to release this update as soon as possible
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- ALTER TABLE "steam_account_credentials" DROP CONSTRAINT "<constraint_name>";--> statement-breakpoint
|
||||||
|
ALTER TABLE "images" ALTER COLUMN "source_url" DROP NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_account_credentials" ADD CONSTRAINT "steam_account_credentials_steam_id_id_pk" PRIMARY KEY("steam_id","id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_account_credentials" ADD COLUMN "id" char(30) NOT NULL;
|
||||||
23
packages/core/migrations/0020_vengeful_wallop.sql
Normal file
23
packages/core/migrations/0020_vengeful_wallop.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
ALTER TABLE "steam_account_credentials" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||||
|
DROP TABLE "steam_account_credentials" CASCADE;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" RENAME COLUMN "owner_id" TO "owner_steam_id";--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" RENAME COLUMN "owner_id" TO "owner_steam_id";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_accounts" DROP CONSTRAINT "idx_steam_username";--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" DROP CONSTRAINT "game_libraries_owner_id_steam_accounts_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" DROP CONSTRAINT "teams_owner_id_users_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" DROP CONSTRAINT "teams_slug_steam_accounts_username_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
DROP INDEX "idx_team_slug";--> statement-breakpoint
|
||||||
|
DROP INDEX "idx_game_libraries_owner_id";--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" DROP CONSTRAINT "game_libraries_base_game_id_owner_id_pk";--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ALTER COLUMN "last_played" DROP NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD CONSTRAINT "game_libraries_base_game_id_owner_steam_id_pk" PRIMARY KEY("base_game_id","owner_steam_id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" ADD CONSTRAINT "game_libraries_owner_steam_id_steam_accounts_id_fk" FOREIGN KEY ("owner_steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" ADD CONSTRAINT "teams_owner_steam_id_steam_accounts_id_fk" FOREIGN KEY ("owner_steam_id") REFERENCES "public"."steam_accounts"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE INDEX "idx_game_libraries_owner_id" ON "game_libraries" USING btree ("owner_steam_id");--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" DROP COLUMN "time_acquired";--> statement-breakpoint
|
||||||
|
ALTER TABLE "game_libraries" DROP COLUMN "is_family_shared";--> statement-breakpoint
|
||||||
|
ALTER TABLE "steam_accounts" DROP COLUMN "username";--> statement-breakpoint
|
||||||
|
ALTER TABLE "teams" DROP COLUMN "slug";
|
||||||
2
packages/core/migrations/0021_real_skreet.sql
Normal file
2
packages/core/migrations/0021_real_skreet.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TYPE "public"."category_type" ADD VALUE 'category';--> statement-breakpoint
|
||||||
|
ALTER TYPE "public"."category_type" ADD VALUE 'franchise';
|
||||||
6
packages/core/migrations/0022_clean_living_lightning.sql
Normal file
6
packages/core/migrations/0022_clean_living_lightning.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
ALTER TABLE "public"."categories" ALTER COLUMN "type" SET DATA TYPE text;--> statement-breakpoint
|
||||||
|
ALTER TABLE "public"."games" ALTER COLUMN "type" SET DATA TYPE text;--> statement-breakpoint
|
||||||
|
DROP TYPE "public"."category_type";--> statement-breakpoint
|
||||||
|
CREATE TYPE "public"."category_type" AS ENUM('tag', 'genre', 'publisher', 'developer', 'categorie', 'franchise');--> statement-breakpoint
|
||||||
|
ALTER TABLE "public"."categories" ALTER COLUMN "type" SET DATA TYPE "public"."category_type" USING "type"::"public"."category_type";--> statement-breakpoint
|
||||||
|
ALTER TABLE "public"."games" ALTER COLUMN "type" SET DATA TYPE "public"."category_type" USING "type"::"public"."category_type";
|
||||||
2
packages/core/migrations/0023_flawless_steel_serpent.sql
Normal file
2
packages/core/migrations/0023_flawless_steel_serpent.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE "base_games" ALTER COLUMN "description" DROP NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "base_games" ADD COLUMN "links" text[];
|
||||||
1
packages/core/migrations/0024_damp_cerise.sql
Normal file
1
packages/core/migrations/0024_damp_cerise.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "base_games" ALTER COLUMN "links" SET DATA TYPE json;
|
||||||
3
packages/core/migrations/0025_bitter_jack_flag.sql
Normal file
3
packages/core/migrations/0025_bitter_jack_flag.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
DROP TABLE "members" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TABLE "teams" CASCADE;--> statement-breakpoint
|
||||||
|
DROP TYPE "public"."member_role";
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"id": "08ba0262-ce0a-4d87-b4e2-0d17dc0ee28c",
|
"id": "f09034df-208a-42b3-b61f-f842921c6e24",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
@@ -54,6 +54,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
"member_email": {
|
"member_email": {
|
||||||
"name": "member_email",
|
"name": "member_email",
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -74,21 +89,6 @@
|
|||||||
"concurrently": false,
|
"concurrently": false,
|
||||||
"method": "btree",
|
"method": "btree",
|
||||||
"with": {}
|
"with": {}
|
||||||
},
|
|
||||||
"email_global": {
|
|
||||||
"name": "email_global",
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"expression": "email",
|
|
||||||
"isExpression": false,
|
|
||||||
"asc": true,
|
|
||||||
"nulls": "last"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isUnique": false,
|
|
||||||
"concurrently": false,
|
|
||||||
"method": "btree",
|
|
||||||
"with": {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
@@ -136,22 +136,28 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"name": {
|
"plan_type": {
|
||||||
"name": "name",
|
"name": "plan_type",
|
||||||
"type": "varchar(255)",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"slug": {
|
"team_slug": {
|
||||||
"name": "slug",
|
"name": "team_slug",
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"expression": "slug",
|
"expression": "slug",
|
||||||
@@ -209,12 +215,6 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
"email": {
|
|
||||||
"name": "email",
|
|
||||||
"type": "varchar(255)",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
@@ -227,11 +227,24 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
"polar_customer_id": {
|
"polar_customer_id": {
|
||||||
"name": "polar_customer_id",
|
"name": "polar_customer_id",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": false
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"name": "flags",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "c09359df-19fe-4246-9a41-43b3a429c12f",
|
"id": "6f428226-b5d8-4182-a676-d04f842f9ded",
|
||||||
"prevId": "08ba0262-ce0a-4d87-b4e2-0d17dc0ee28c",
|
"prevId": "f09034df-208a-42b3-b61f-f842921c6e24",
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
@@ -54,6 +54,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
"member_email": {
|
"member_email": {
|
||||||
"name": "member_email",
|
"name": "member_email",
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -74,21 +89,6 @@
|
|||||||
"concurrently": false,
|
"concurrently": false,
|
||||||
"method": "btree",
|
"method": "btree",
|
||||||
"with": {}
|
"with": {}
|
||||||
},
|
|
||||||
"email_global": {
|
|
||||||
"name": "email_global",
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"expression": "email",
|
|
||||||
"isExpression": false,
|
|
||||||
"asc": true,
|
|
||||||
"nulls": "last"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"isUnique": false,
|
|
||||||
"concurrently": false,
|
|
||||||
"method": "btree",
|
|
||||||
"with": {}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
@@ -136,15 +136,21 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
"slug": {
|
"slug": {
|
||||||
"name": "slug",
|
"name": "slug",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"name": {
|
"plan_type": {
|
||||||
"name": "name",
|
"name": "plan_type",
|
||||||
"type": "varchar(255)",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
}
|
}
|
||||||
@@ -209,12 +215,6 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
"email": {
|
|
||||||
"name": "email",
|
|
||||||
"type": "varchar(255)",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
@@ -227,11 +227,24 @@
|
|||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
"polar_customer_id": {
|
"polar_customer_id": {
|
||||||
"name": "polar_customer_id",
|
"name": "polar_customer_id",
|
||||||
"type": "varchar(255)",
|
"type": "varchar(255)",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"name": "flags",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
|
|||||||
420
packages/core/migrations/meta/0002_snapshot.json
Normal file
420
packages/core/migrations/meta/0002_snapshot.json
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
{
|
||||||
|
"id": "227c54d2-b643-48d5-964b-af6fe004369a",
|
||||||
|
"prevId": "6f428226-b5d8-4182-a676-d04f842f9ded",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"access_token": {
|
||||||
|
"name": "access_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"global_steam_email": {
|
||||||
|
"name": "global_steam_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"steam_user_id_id_pk": {
|
||||||
|
"name": "steam_user_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"user_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"name": "flags",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": "'{}'::json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
507
packages/core/migrations/meta/0003_snapshot.json
Normal file
507
packages/core/migrations/meta/0003_snapshot.json
Normal file
@@ -0,0 +1,507 @@
|
|||||||
|
{
|
||||||
|
"id": "eb5d41aa-5f85-4b2d-8633-fc021b211241",
|
||||||
|
"prevId": "227c54d2-b643-48d5-964b-af6fe004369a",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"steam_user_id_id_pk": {
|
||||||
|
"name": "steam_user_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"user_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
499
packages/core/migrations/meta/0004_snapshot.json
Normal file
499
packages/core/migrations/meta/0004_snapshot.json
Normal file
@@ -0,0 +1,499 @@
|
|||||||
|
{
|
||||||
|
"id": "65574f71-e0d3-4363-9449-394e7c376a30",
|
||||||
|
"prevId": "eb5d41aa-5f85-4b2d-8633-fc021b211241",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"machine_user_id_id_pk": {
|
||||||
|
"name": "machine_user_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"user_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
485
packages/core/migrations/meta/0005_snapshot.json
Normal file
485
packages/core/migrations/meta/0005_snapshot.json
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
{
|
||||||
|
"id": "0b04858c-a7e3-43b6-98a4-1dc2f6f97488",
|
||||||
|
"prevId": "65574f71-e0d3-4363-9449-394e7c376a30",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
485
packages/core/migrations/meta/0006_snapshot.json
Normal file
485
packages/core/migrations/meta/0006_snapshot.json
Normal file
@@ -0,0 +1,485 @@
|
|||||||
|
{
|
||||||
|
"id": "69827225-1351-4709-a9b2-facb0f569215",
|
||||||
|
"prevId": "0b04858c-a7e3-43b6-98a4-1dc2f6f97488",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
580
packages/core/migrations/meta/0007_snapshot.json
Normal file
580
packages/core/migrations/meta/0007_snapshot.json
Normal file
@@ -0,0 +1,580 @@
|
|||||||
|
{
|
||||||
|
"id": "fff2b73d-85ab-48bc-86de-69d3caf317f0",
|
||||||
|
"prevId": "69827225-1351-4709-a9b2-facb0f569215",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.subscription": {
|
||||||
|
"name": "subscription",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"standing": {
|
||||||
|
"name": "standing",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"tokens": {
|
||||||
|
"name": "tokens",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"product_id": {
|
||||||
|
"name": "product_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"subscription_id": {
|
||||||
|
"name": "subscription_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"subscription_team_id_team_id_fk": {
|
||||||
|
"name": "subscription_team_id_team_id_fk",
|
||||||
|
"tableFrom": "subscription",
|
||||||
|
"tableTo": "team",
|
||||||
|
"columnsFrom": [
|
||||||
|
"team_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
619
packages/core/migrations/meta/0008_snapshot.json
Normal file
619
packages/core/migrations/meta/0008_snapshot.json
Normal file
@@ -0,0 +1,619 @@
|
|||||||
|
{
|
||||||
|
"id": "17b9c14f-ff15-44a5-9aaf-3f3b7dd7d294",
|
||||||
|
"prevId": "fff2b73d-85ab-48bc-86de-69d3caf317f0",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.subscription": {
|
||||||
|
"name": "subscription",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"standing": {
|
||||||
|
"name": "standing",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"tokens": {
|
||||||
|
"name": "tokens",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"product_id": {
|
||||||
|
"name": "product_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"subscription_id": {
|
||||||
|
"name": "subscription_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"subscription_id": {
|
||||||
|
"name": "subscription_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"subscription_user_id": {
|
||||||
|
"name": "subscription_user_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"subscription_team_id_team_id_fk": {
|
||||||
|
"name": "subscription_team_id_team_id_fk",
|
||||||
|
"tableFrom": "subscription",
|
||||||
|
"tableTo": "team",
|
||||||
|
"columnsFrom": [
|
||||||
|
"team_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"subscription_id_team_id_pk": {
|
||||||
|
"name": "subscription_id_team_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"team_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
650
packages/core/migrations/meta/0009_snapshot.json
Normal file
650
packages/core/migrations/meta/0009_snapshot.json
Normal file
@@ -0,0 +1,650 @@
|
|||||||
|
{
|
||||||
|
"id": "1717c769-cee0-4242-bcbb-9538c80d985c",
|
||||||
|
"prevId": "17b9c14f-ff15-44a5-9aaf-3f3b7dd7d294",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.machine": {
|
||||||
|
"name": "machine",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"country": {
|
||||||
|
"name": "country",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"timezone": {
|
||||||
|
"name": "timezone",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "point",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"name": "fingerprint",
|
||||||
|
"type": "varchar(32)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"machine_fingerprint": {
|
||||||
|
"name": "machine_fingerprint",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "fingerprint",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.member": {
|
||||||
|
"name": "member",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_seen": {
|
||||||
|
"name": "time_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"email_global": {
|
||||||
|
"name": "email_global",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"member_email": {
|
||||||
|
"name": "member_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"member_team_id_id_pk": {
|
||||||
|
"name": "member_team_id_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"team_id",
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam": {
|
||||||
|
"name": "steam",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_seen": {
|
||||||
|
"name": "last_seen",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_game": {
|
||||||
|
"name": "last_game",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"country_code": {
|
||||||
|
"name": "country_code",
|
||||||
|
"type": "varchar(2)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"steam_email": {
|
||||||
|
"name": "steam_email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"persona_name": {
|
||||||
|
"name": "persona_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitation": {
|
||||||
|
"name": "limitation",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "steam_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"steam_user_id": {
|
||||||
|
"name": "steam_user_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_user_id_user_id_fk": {
|
||||||
|
"name": "steam_user_id_user_id_fk",
|
||||||
|
"tableFrom": "steam",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.subscription": {
|
||||||
|
"name": "subscription",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"standing": {
|
||||||
|
"name": "standing",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"plan_type": {
|
||||||
|
"name": "plan_type",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"tokens": {
|
||||||
|
"name": "tokens",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"product_id": {
|
||||||
|
"name": "product_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"subscription_id": {
|
||||||
|
"name": "subscription_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"subscription_id": {
|
||||||
|
"name": "subscription_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"subscription_user_id": {
|
||||||
|
"name": "subscription_user_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"subscription_team_id_team_id_fk": {
|
||||||
|
"name": "subscription_team_id_team_id_fk",
|
||||||
|
"tableFrom": "subscription",
|
||||||
|
"tableTo": "team",
|
||||||
|
"columnsFrom": [
|
||||||
|
"team_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"subscription_id_team_id_pk": {
|
||||||
|
"name": "subscription_id_team_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"team_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.team": {
|
||||||
|
"name": "team",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.user": {
|
||||||
|
"name": "user",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"discriminator": {
|
||||||
|
"name": "discriminator",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"user_email": {
|
||||||
|
"name": "user_email",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "email",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"user_polar_customer_id_unique": {
|
||||||
|
"name": "user_polar_customer_id_unique",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"polar_customer_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
651
packages/core/migrations/meta/0010_snapshot.json
Normal file
651
packages/core/migrations/meta/0010_snapshot.json
Normal file
@@ -0,0 +1,651 @@
|
|||||||
|
{
|
||||||
|
"id": "56a4d60a-c062-47e5-a97e-625443411ad8",
|
||||||
|
"prevId": "1717c769-cee0-4242-bcbb-9538c80d985c",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.steam_account_credentials": {
|
||||||
|
"name": "steam_account_credentials",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"refresh_token": {
|
||||||
|
"name": "refresh_token",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"expiry": {
|
||||||
|
"name": "expiry",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_account_credentials_steam_id_steam_accounts_steam_id_fk": {
|
||||||
|
"name": "steam_account_credentials_steam_id_steam_accounts_steam_id_fk",
|
||||||
|
"tableFrom": "steam_account_credentials",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.friends_list": {
|
||||||
|
"name": "friends_list",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"friend_steam_id": {
|
||||||
|
"name": "friend_steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"friends_list_steam_id_steam_accounts_steam_id_fk": {
|
||||||
|
"name": "friends_list_steam_id_steam_accounts_steam_id_fk",
|
||||||
|
"tableFrom": "friends_list",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"friends_list_friend_steam_id_steam_accounts_steam_id_fk": {
|
||||||
|
"name": "friends_list_friend_steam_id_steam_accounts_steam_id_fk",
|
||||||
|
"tableFrom": "friends_list",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"friend_steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"friends_list_steam_id_friend_steam_id_pk": {
|
||||||
|
"name": "friends_list_steam_id_friend_steam_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"steam_id",
|
||||||
|
"friend_steam_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.members": {
|
||||||
|
"name": "members",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"team_id": {
|
||||||
|
"name": "team_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "member_role",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_member_steam_id": {
|
||||||
|
"name": "idx_member_steam_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "steam_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"idx_member_user_id": {
|
||||||
|
"name": "idx_member_user_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "team_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "user_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"where": "\"members\".\"user_id\" is not null",
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"members_user_id_users_id_fk": {
|
||||||
|
"name": "members_user_id_users_id_fk",
|
||||||
|
"tableFrom": "members",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"members_steam_id_steam_accounts_steam_id_fk": {
|
||||||
|
"name": "members_steam_id_steam_accounts_steam_id_fk",
|
||||||
|
"tableFrom": "members",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "restrict"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"members_id_team_id_pk": {
|
||||||
|
"name": "members_id_team_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"id",
|
||||||
|
"team_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam_accounts": {
|
||||||
|
"name": "steam_accounts",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "steam_status",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_synced_at": {
|
||||||
|
"name": "last_synced_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"real_name": {
|
||||||
|
"name": "real_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"member_since": {
|
||||||
|
"name": "member_since",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"profile_url": {
|
||||||
|
"name": "profile_url",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"name": "username",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_hash": {
|
||||||
|
"name": "avatar_hash",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitations": {
|
||||||
|
"name": "limitations",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_accounts_user_id_users_id_fk": {
|
||||||
|
"name": "steam_accounts_user_id_users_id_fk",
|
||||||
|
"tableFrom": "steam_accounts",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"idx_steam_username": {
|
||||||
|
"name": "idx_steam_username",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"username"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.teams": {
|
||||||
|
"name": "teams",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"owner_id": {
|
||||||
|
"name": "owner_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"invite_code": {
|
||||||
|
"name": "invite_code",
|
||||||
|
"type": "varchar(10)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"max_members": {
|
||||||
|
"name": "max_members",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_team_slug": {
|
||||||
|
"name": "idx_team_slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": true,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"teams_owner_id_users_id_fk": {
|
||||||
|
"name": "teams_owner_id_users_id_fk",
|
||||||
|
"tableFrom": "teams",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"owner_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"teams_slug_steam_accounts_username_fk": {
|
||||||
|
"name": "teams_slug_steam_accounts_username_fk",
|
||||||
|
"tableFrom": "teams",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"slug"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"username"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"idx_team_invite_code": {
|
||||||
|
"name": "idx_team_invite_code",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"invite_code"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"last_login": {
|
||||||
|
"name": "last_login",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"idx_user_email": {
|
||||||
|
"name": "idx_user_email",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"public.member_role": {
|
||||||
|
"name": "member_role",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"child",
|
||||||
|
"adult"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.steam_status": {
|
||||||
|
"name": "steam_status",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"online",
|
||||||
|
"offline",
|
||||||
|
"dnd",
|
||||||
|
"playing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
1235
packages/core/migrations/meta/0011_snapshot.json
Normal file
1235
packages/core/migrations/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1256
packages/core/migrations/meta/0012_snapshot.json
Normal file
1256
packages/core/migrations/meta/0012_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1265
packages/core/migrations/meta/0013_snapshot.json
Normal file
1265
packages/core/migrations/meta/0013_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1265
packages/core/migrations/meta/0014_snapshot.json
Normal file
1265
packages/core/migrations/meta/0014_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1266
packages/core/migrations/meta/0015_snapshot.json
Normal file
1266
packages/core/migrations/meta/0015_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1290
packages/core/migrations/meta/0016_snapshot.json
Normal file
1290
packages/core/migrations/meta/0016_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1290
packages/core/migrations/meta/0017_snapshot.json
Normal file
1290
packages/core/migrations/meta/0017_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1290
packages/core/migrations/meta/0018_snapshot.json
Normal file
1290
packages/core/migrations/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1304
packages/core/migrations/meta/0019_snapshot.json
Normal file
1304
packages/core/migrations/meta/0019_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1158
packages/core/migrations/meta/0020_snapshot.json
Normal file
1158
packages/core/migrations/meta/0020_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1160
packages/core/migrations/meta/0021_snapshot.json
Normal file
1160
packages/core/migrations/meta/0021_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1160
packages/core/migrations/meta/0022_snapshot.json
Normal file
1160
packages/core/migrations/meta/0022_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1166
packages/core/migrations/meta/0023_snapshot.json
Normal file
1166
packages/core/migrations/meta/0023_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1166
packages/core/migrations/meta/0024_snapshot.json
Normal file
1166
packages/core/migrations/meta/0024_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
930
packages/core/migrations/meta/0025_snapshot.json
Normal file
930
packages/core/migrations/meta/0025_snapshot.json
Normal file
@@ -0,0 +1,930 @@
|
|||||||
|
{
|
||||||
|
"id": "735d315b-40e1-46c1-814d-0fd3619b65de",
|
||||||
|
"prevId": "d35aa09b-5739-46a5-86f3-3050913dc2f7",
|
||||||
|
"version": "7",
|
||||||
|
"dialect": "postgresql",
|
||||||
|
"tables": {
|
||||||
|
"public.base_games": {
|
||||||
|
"name": "base_games",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"name": "links",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"name": "description",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"release_date": {
|
||||||
|
"name": "release_date",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"name": "size",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"primary_genre": {
|
||||||
|
"name": "primary_genre",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"controller_support": {
|
||||||
|
"name": "controller_support",
|
||||||
|
"type": "controller_support",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"compatibility": {
|
||||||
|
"name": "compatibility",
|
||||||
|
"type": "compatibility",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'unknown'"
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"name": "score",
|
||||||
|
"type": "numeric(2, 1)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"idx_base_games_slug": {
|
||||||
|
"name": "idx_base_games_slug",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"slug"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.categories": {
|
||||||
|
"name": "categories",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"name": "slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "category_type",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_categories_type": {
|
||||||
|
"name": "idx_categories_type",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "type",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"categories_slug_type_pk": {
|
||||||
|
"name": "categories_slug_type_pk",
|
||||||
|
"columns": [
|
||||||
|
"slug",
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.friends_list": {
|
||||||
|
"name": "friends_list",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"steam_id": {
|
||||||
|
"name": "steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"friend_steam_id": {
|
||||||
|
"name": "friend_steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_friends_list_friend_steam_id": {
|
||||||
|
"name": "idx_friends_list_friend_steam_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "friend_steam_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"friends_list_steam_id_steam_accounts_id_fk": {
|
||||||
|
"name": "friends_list_steam_id_steam_accounts_id_fk",
|
||||||
|
"tableFrom": "friends_list",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"friends_list_friend_steam_id_steam_accounts_id_fk": {
|
||||||
|
"name": "friends_list_friend_steam_id_steam_accounts_id_fk",
|
||||||
|
"tableFrom": "friends_list",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"friend_steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"friends_list_steam_id_friend_steam_id_pk": {
|
||||||
|
"name": "friends_list_steam_id_friend_steam_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"steam_id",
|
||||||
|
"friend_steam_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.games": {
|
||||||
|
"name": "games",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"base_game_id": {
|
||||||
|
"name": "base_game_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"category_slug": {
|
||||||
|
"name": "category_slug",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "category_type",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_games_category_slug": {
|
||||||
|
"name": "idx_games_category_slug",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "category_slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"idx_games_category_type": {
|
||||||
|
"name": "idx_games_category_type",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "type",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"idx_games_category_slug_type": {
|
||||||
|
"name": "idx_games_category_slug_type",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "category_slug",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"expression": "type",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"games_base_game_id_base_games_id_fk": {
|
||||||
|
"name": "games_base_game_id_base_games_id_fk",
|
||||||
|
"tableFrom": "games",
|
||||||
|
"tableTo": "base_games",
|
||||||
|
"columnsFrom": [
|
||||||
|
"base_game_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"games_categories_fkey": {
|
||||||
|
"name": "games_categories_fkey",
|
||||||
|
"tableFrom": "games",
|
||||||
|
"tableTo": "categories",
|
||||||
|
"columnsFrom": [
|
||||||
|
"category_slug",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"slug",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"games_base_game_id_category_slug_type_pk": {
|
||||||
|
"name": "games_base_game_id_category_slug_type_pk",
|
||||||
|
"columns": [
|
||||||
|
"base_game_id",
|
||||||
|
"category_slug",
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.images": {
|
||||||
|
"name": "images",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"name": "type",
|
||||||
|
"type": "image_type",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"image_hash": {
|
||||||
|
"name": "image_hash",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"base_game_id": {
|
||||||
|
"name": "base_game_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"source_url": {
|
||||||
|
"name": "source_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"name": "position",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"file_size": {
|
||||||
|
"name": "file_size",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"dimensions": {
|
||||||
|
"name": "dimensions",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"extracted_color": {
|
||||||
|
"name": "extracted_color",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_images_type": {
|
||||||
|
"name": "idx_images_type",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "type",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
},
|
||||||
|
"idx_images_game_id": {
|
||||||
|
"name": "idx_images_game_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "base_game_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"images_base_game_id_base_games_id_fk": {
|
||||||
|
"name": "images_base_game_id_base_games_id_fk",
|
||||||
|
"tableFrom": "images",
|
||||||
|
"tableTo": "base_games",
|
||||||
|
"columnsFrom": [
|
||||||
|
"base_game_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"images_image_hash_type_base_game_id_position_pk": {
|
||||||
|
"name": "images_image_hash_type_base_game_id_position_pk",
|
||||||
|
"columns": [
|
||||||
|
"image_hash",
|
||||||
|
"type",
|
||||||
|
"base_game_id",
|
||||||
|
"position"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.game_libraries": {
|
||||||
|
"name": "game_libraries",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"base_game_id": {
|
||||||
|
"name": "base_game_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"owner_steam_id": {
|
||||||
|
"name": "owner_steam_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_played": {
|
||||||
|
"name": "last_played",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"total_playtime": {
|
||||||
|
"name": "total_playtime",
|
||||||
|
"type": "integer",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_game_libraries_owner_id": {
|
||||||
|
"name": "idx_game_libraries_owner_id",
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"expression": "owner_steam_id",
|
||||||
|
"isExpression": false,
|
||||||
|
"asc": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "btree",
|
||||||
|
"with": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"game_libraries_base_game_id_base_games_id_fk": {
|
||||||
|
"name": "game_libraries_base_game_id_base_games_id_fk",
|
||||||
|
"tableFrom": "game_libraries",
|
||||||
|
"tableTo": "base_games",
|
||||||
|
"columnsFrom": [
|
||||||
|
"base_game_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"game_libraries_owner_steam_id_steam_accounts_id_fk": {
|
||||||
|
"name": "game_libraries_owner_steam_id_steam_accounts_id_fk",
|
||||||
|
"tableFrom": "game_libraries",
|
||||||
|
"tableTo": "steam_accounts",
|
||||||
|
"columnsFrom": [
|
||||||
|
"owner_steam_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"game_libraries_base_game_id_owner_steam_id_pk": {
|
||||||
|
"name": "game_libraries_base_game_id_owner_steam_id_pk",
|
||||||
|
"columns": [
|
||||||
|
"base_game_id",
|
||||||
|
"owner_steam_id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.steam_accounts": {
|
||||||
|
"name": "steam_accounts",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "steam_status",
|
||||||
|
"typeSchema": "public",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"last_synced_at": {
|
||||||
|
"name": "last_synced_at",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"real_name": {
|
||||||
|
"name": "real_name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"member_since": {
|
||||||
|
"name": "member_since",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"profile_url": {
|
||||||
|
"name": "profile_url",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"avatar_hash": {
|
||||||
|
"name": "avatar_hash",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"limitations": {
|
||||||
|
"name": "limitations",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"steam_accounts_user_id_users_id_fk": {
|
||||||
|
"name": "steam_accounts_user_id_users_id_fk",
|
||||||
|
"tableFrom": "steam_accounts",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
},
|
||||||
|
"public.users": {
|
||||||
|
"name": "users",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "char(30)",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"time_created": {
|
||||||
|
"name": "time_created",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_updated": {
|
||||||
|
"name": "time_updated",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "now()"
|
||||||
|
},
|
||||||
|
"time_deleted": {
|
||||||
|
"name": "time_deleted",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"name": "email",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"avatar_url": {
|
||||||
|
"name": "avatar_url",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"last_login": {
|
||||||
|
"name": "last_login",
|
||||||
|
"type": "timestamp with time zone",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"polar_customer_id": {
|
||||||
|
"name": "polar_customer_id",
|
||||||
|
"type": "varchar(255)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {
|
||||||
|
"idx_user_email": {
|
||||||
|
"name": "idx_user_email",
|
||||||
|
"nullsNotDistinct": false,
|
||||||
|
"columns": [
|
||||||
|
"email"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"policies": {},
|
||||||
|
"checkConstraints": {},
|
||||||
|
"isRLSEnabled": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {
|
||||||
|
"public.compatibility": {
|
||||||
|
"name": "compatibility",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"high",
|
||||||
|
"mid",
|
||||||
|
"low",
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.controller_support": {
|
||||||
|
"name": "controller_support",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"full",
|
||||||
|
"partial",
|
||||||
|
"unknown"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.category_type": {
|
||||||
|
"name": "category_type",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"tag",
|
||||||
|
"genre",
|
||||||
|
"publisher",
|
||||||
|
"developer",
|
||||||
|
"categorie",
|
||||||
|
"franchise"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.image_type": {
|
||||||
|
"name": "image_type",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"heroArt",
|
||||||
|
"icon",
|
||||||
|
"logo",
|
||||||
|
"banner",
|
||||||
|
"poster",
|
||||||
|
"boxArt",
|
||||||
|
"screenshot",
|
||||||
|
"backdrop"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"public.steam_status": {
|
||||||
|
"name": "steam_status",
|
||||||
|
"schema": "public",
|
||||||
|
"values": [
|
||||||
|
"online",
|
||||||
|
"offline",
|
||||||
|
"dnd",
|
||||||
|
"playing"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {},
|
||||||
|
"sequences": {},
|
||||||
|
"roles": {},
|
||||||
|
"policies": {},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,15 +5,183 @@
|
|||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1740345380808,
|
"when": 1741759978256,
|
||||||
"tag": "0000_wise_black_widow",
|
"tag": "0000_flaky_matthew_murdock",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1740487217291,
|
"when": 1741955636085,
|
||||||
"tag": "0001_flaky_tomorrow_man",
|
"tag": "0001_nifty_sauron",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1743794969007,
|
||||||
|
"tag": "0002_simple_outlaw_kid",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 3,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744287542918,
|
||||||
|
"tag": "0003_first_big_bertha",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 4,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744614629788,
|
||||||
|
"tag": "0004_amused_mattie_franklin",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 5,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744614896792,
|
||||||
|
"tag": "0005_aspiring_stature",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 6,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744634229644,
|
||||||
|
"tag": "0006_worthless_dreadnoughts",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 7,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744634322996,
|
||||||
|
"tag": "0007_warm_secret_warriors",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 8,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744651530530,
|
||||||
|
"tag": "0008_third_mindworm",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 9,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1744651817581,
|
||||||
|
"tag": "0009_luxuriant_wraith",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 10,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746726715456,
|
||||||
|
"tag": "0010_certain_dust",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746904821461,
|
||||||
|
"tag": "0011_simple_azazel",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 12,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746905730079,
|
||||||
|
"tag": "0012_glorious_jetstream",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 13,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746925065142,
|
||||||
|
"tag": "0013_neat_colleen_wing",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 14,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746926498096,
|
||||||
|
"tag": "0014_thin_groot",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 15,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1746928882281,
|
||||||
|
"tag": "0015_handy_giant_man",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 16,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747032794033,
|
||||||
|
"tag": "0016_melted_johnny_storm",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 17,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747034424687,
|
||||||
|
"tag": "0017_zippy_nico_minoru",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 18,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747073173196,
|
||||||
|
"tag": "0018_solid_enchantress",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 19,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747202158003,
|
||||||
|
"tag": "0019_charming_namorita",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 20,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747795508868,
|
||||||
|
"tag": "0020_vengeful_wallop",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 21,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1747975397543,
|
||||||
|
"tag": "0021_real_skreet",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 22,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1748099972605,
|
||||||
|
"tag": "0022_clean_living_lightning",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 23,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1748411845939,
|
||||||
|
"tag": "0023_flawless_steel_serpent",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 24,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1748414049463,
|
||||||
|
"tag": "0024_damp_cerise",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 25,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1748845818197,
|
||||||
|
"tag": "0025_bitter_jack_flag",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,37 +4,46 @@
|
|||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"db:dev": "drizzle-kit",
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
"db": "sst shell drizzle-kit",
|
"db": "sst shell drizzle-kit",
|
||||||
"db:push": "sst shell drizzle-kit push",
|
"db:exec": "sst shell ../scripts/src/psql.sh",
|
||||||
"db:migrate": "sst shell drizzle-kit migrate",
|
"db:reset": "sst shell ../scripts/src/db-reset.sh"
|
||||||
"db:generate": "sst shell drizzle-kit generate",
|
|
||||||
"db:connect": "sst shell ../scripts/src/psql.ts",
|
|
||||||
"db:move": "sst shell drizzle-kit generate && sst shell drizzle-kit migrate && sst shell drizzle-kit push"
|
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./*": "./src/*.ts"
|
"./*": "./src/*.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node20": "^20.1.4",
|
"@tsconfig/node20": "^20.1.4",
|
||||||
|
"@types/pngjs": "^6.0.5",
|
||||||
|
"@types/sanitize-html": "^2.16.0",
|
||||||
|
"@types/xml2js": "^0.4.14",
|
||||||
"aws-iot-device-sdk-v2": "^1.21.1",
|
"aws-iot-device-sdk-v2": "^1.21.1",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"drizzle-kit": "^0.30.4",
|
|
||||||
"loops": "^3.4.1",
|
|
||||||
"mqtt": "^5.10.3",
|
"mqtt": "^5.10.3",
|
||||||
"remeda": "^2.19.0",
|
"remeda": "^2.21.2",
|
||||||
"ulid": "^2.3.0",
|
"ulid": "^2.3.0",
|
||||||
"uuid": "^11.0.3",
|
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.1",
|
||||||
"zod-openapi": "^4.2.2"
|
"zod-openapi": "^4.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-iot-data-plane": "^3.758.0",
|
||||||
"@aws-sdk/client-sesv2": "^3.753.0",
|
"@aws-sdk/client-sesv2": "^3.753.0",
|
||||||
"@instantdb/admin": "^0.17.7",
|
"@openauthjs/openauth": "*",
|
||||||
"@neondatabase/serverless": "^0.10.4",
|
|
||||||
"@openauthjs/openauth": "0.4.3",
|
|
||||||
"@openauthjs/openevent": "^0.0.27",
|
"@openauthjs/openevent": "^0.0.27",
|
||||||
"@polar-sh/sdk": "^0.26.1",
|
"@polar-sh/sdk": "^0.26.1",
|
||||||
"drizzle-orm": "^0.39.3",
|
"drizzle-kit": "^0.30.5",
|
||||||
"ws": "^8.18.1"
|
"drizzle-orm": "^0.40.0",
|
||||||
|
"drizzle-zod": "^0.7.1",
|
||||||
|
"fast-average-color": "^9.5.0",
|
||||||
|
"lru-cache": "^11.1.0",
|
||||||
|
"p-limit": "^6.2.0",
|
||||||
|
"pixelmatch": "^7.1.0",
|
||||||
|
"pngjs": "^7.0.0",
|
||||||
|
"postgres": "^3.4.5",
|
||||||
|
"sanitize-html": "^2.16.0",
|
||||||
|
"sharp": "^0.34.1",
|
||||||
|
"steam-session": "*",
|
||||||
|
"xml2js": "^0.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
packages/core/src/account/index.ts
Normal file
47
packages/core/src/account/index.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { User } from "../user";
|
||||||
|
import { Steam } from "../steam";
|
||||||
|
import { Actor } from "../actor";
|
||||||
|
import { Examples } from "../examples";
|
||||||
|
import { ErrorCodes, VisibleError } from "../error";
|
||||||
|
|
||||||
|
export namespace Account {
|
||||||
|
export const Info =
|
||||||
|
User.Info
|
||||||
|
.extend({
|
||||||
|
profiles: Steam.Info
|
||||||
|
.array()
|
||||||
|
.openapi({
|
||||||
|
description: "The Steam accounts this user owns",
|
||||||
|
example: [Examples.SteamAccount]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.openapi({
|
||||||
|
ref: "Account",
|
||||||
|
description: "Represents an account's information stored on Nestri",
|
||||||
|
example: { ...Examples.User, profiles: [Examples.SteamAccount] },
|
||||||
|
});
|
||||||
|
|
||||||
|
export type Info = z.infer<typeof Info>;
|
||||||
|
|
||||||
|
export const list = async (): Promise<Info> => {
|
||||||
|
const [userResult, steamResult] =
|
||||||
|
await Promise.allSettled([
|
||||||
|
User.fromID(Actor.userID()),
|
||||||
|
Steam.list()
|
||||||
|
])
|
||||||
|
|
||||||
|
if (userResult.status === "rejected" || !userResult.value)
|
||||||
|
throw new VisibleError(
|
||||||
|
"not_found",
|
||||||
|
ErrorCodes.NotFound.RESOURCE_NOT_FOUND,
|
||||||
|
"User not found",
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...userResult.value,
|
||||||
|
profiles: steamResult.status === "rejected" ? [] : steamResult.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,92 +1,130 @@
|
|||||||
import { z } from "zod";
|
import { Log } from "./utils";
|
||||||
import { eq } from "./drizzle";
|
|
||||||
import { VisibleError } from "./error";
|
|
||||||
import { createContext } from "./context";
|
import { createContext } from "./context";
|
||||||
import { UserFlags, userTable } from "./user/user.sql";
|
import { ErrorCodes, VisibleError } from "./error";
|
||||||
import { useTransaction } from "./drizzle/transaction";
|
|
||||||
|
|
||||||
export const PublicActor = z.object({
|
export namespace Actor {
|
||||||
type: z.literal("public"),
|
|
||||||
properties: z.object({}),
|
|
||||||
});
|
|
||||||
export type PublicActor = z.infer<typeof PublicActor>;
|
|
||||||
|
|
||||||
export const UserActor = z.object({
|
export interface User {
|
||||||
type: z.literal("user"),
|
type: "user";
|
||||||
properties: z.object({
|
properties: {
|
||||||
userID: z.string(),
|
userID: string;
|
||||||
email: z.string().nonempty(),
|
email: string;
|
||||||
}),
|
};
|
||||||
});
|
|
||||||
export type UserActor = z.infer<typeof UserActor>;
|
|
||||||
|
|
||||||
export const MemberActor = z.object({
|
|
||||||
type: z.literal("member"),
|
|
||||||
properties: z.object({
|
|
||||||
memberID: z.string(),
|
|
||||||
teamID: z.string(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
export type MemberActor = z.infer<typeof MemberActor>;
|
|
||||||
|
|
||||||
export const SystemActor = z.object({
|
|
||||||
type: z.literal("system"),
|
|
||||||
properties: z.object({
|
|
||||||
teamID: z.string(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
export type SystemActor = z.infer<typeof SystemActor>;
|
|
||||||
|
|
||||||
export const Actor = z.discriminatedUnion("type", [
|
|
||||||
MemberActor,
|
|
||||||
UserActor,
|
|
||||||
PublicActor,
|
|
||||||
SystemActor,
|
|
||||||
]);
|
|
||||||
export type Actor = z.infer<typeof Actor>;
|
|
||||||
|
|
||||||
const ActorContext = createContext<Actor>("actor");
|
|
||||||
|
|
||||||
export const useActor = ActorContext.use;
|
|
||||||
export const withActor = ActorContext.with;
|
|
||||||
|
|
||||||
export function useUserID() {
|
|
||||||
const actor = ActorContext.use();
|
|
||||||
if (actor.type === "user") return actor.properties.userID;
|
|
||||||
throw new VisibleError(
|
|
||||||
"unauthorized",
|
|
||||||
`You don't have permission to access this resource`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function assertActor<T extends Actor["type"]>(type: T) {
|
|
||||||
const actor = useActor();
|
|
||||||
if (actor.type !== type) {
|
|
||||||
throw new Error(`Expected actor type ${type}, got ${actor.type}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return actor as Extract<Actor, { type: T }>;
|
export interface Steam {
|
||||||
}
|
type: "steam";
|
||||||
|
properties: {
|
||||||
|
steamID: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function useTeam() {
|
export interface Machine {
|
||||||
const actor = useActor();
|
type: "machine";
|
||||||
if ("teamID" in actor.properties) return actor.properties.teamID;
|
properties: {
|
||||||
throw new Error(`Expected actor to have teamID`);
|
machineID: string;
|
||||||
}
|
fingerprint: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function assertUserFlag(flag: keyof UserFlags) {
|
export interface Token {
|
||||||
return useTransaction((tx) =>
|
type: "member";
|
||||||
tx
|
properties: {
|
||||||
.select({ flags: userTable.flags })
|
userID: string;
|
||||||
.from(userTable)
|
steamID: string;
|
||||||
.where(eq(userTable.id, useUserID()))
|
};
|
||||||
.then((rows) => {
|
}
|
||||||
const flags = rows[0]?.flags;
|
|
||||||
if (!flags)
|
export interface Public {
|
||||||
throw new VisibleError(
|
type: "public";
|
||||||
"user.flags",
|
properties: {};
|
||||||
"Actor does not have " + flag + " flag",
|
}
|
||||||
);
|
|
||||||
}),
|
export type Info = User | Public | Token | Machine | Steam;
|
||||||
);
|
|
||||||
|
export const Context = createContext<Info>();
|
||||||
|
|
||||||
|
export function userID() {
|
||||||
|
const actor = Context.use();
|
||||||
|
if ("userID" in actor.properties) return actor.properties.userID;
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`You don't have permission to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function steamID() {
|
||||||
|
const actor = Context.use();
|
||||||
|
if ("steamID" in actor.properties) return actor.properties.steamID;
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`You don't have permission to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function user() {
|
||||||
|
const actor = Context.use();
|
||||||
|
if (actor.type == "user") return actor.properties;
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`You don't have permission to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function teamID() {
|
||||||
|
const actor = Context.use();
|
||||||
|
if ("teamID" in actor.properties) return actor.properties.teamID;
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`You don't have permission to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fingerprint() {
|
||||||
|
const actor = Context.use();
|
||||||
|
if ("fingerprint" in actor.properties) return actor.properties.fingerprint;
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`You don't have permission to access this resource.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function use() {
|
||||||
|
try {
|
||||||
|
return Context.use();
|
||||||
|
} catch {
|
||||||
|
return { type: "public", properties: {} } as Public;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assert<T extends Info["type"]>(type: T) {
|
||||||
|
const actor = use();
|
||||||
|
if (actor.type !== type)
|
||||||
|
throw new VisibleError(
|
||||||
|
"authentication",
|
||||||
|
ErrorCodes.Authentication.UNAUTHORIZED,
|
||||||
|
`Actor is not "${type}"`,
|
||||||
|
);
|
||||||
|
return actor as Extract<Info, { type: T }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function provide<
|
||||||
|
T extends Info["type"],
|
||||||
|
Next extends (...args: any) => any,
|
||||||
|
>(type: T, properties: Extract<Info, { type: T }>["properties"], fn: Next) {
|
||||||
|
return Context.provide({ type, properties } as any, () =>
|
||||||
|
Log.provide(
|
||||||
|
{
|
||||||
|
actor: type,
|
||||||
|
...properties,
|
||||||
|
},
|
||||||
|
fn,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
44
packages/core/src/base-game/base-game.sql.ts
Normal file
44
packages/core/src/base-game/base-game.sql.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { timestamps, utc } from "../drizzle/types";
|
||||||
|
import { json, numeric, pgEnum, pgTable, text, unique, varchar } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const CompatibilityEnum = pgEnum("compatibility", ["high", "mid", "low", "unknown"])
|
||||||
|
export const ControllerEnum = pgEnum("controller_support", ["full", "partial", "unknown"])
|
||||||
|
|
||||||
|
export const Size =
|
||||||
|
z.object({
|
||||||
|
downloadSize: z.number().positive().int(),
|
||||||
|
sizeOnDisk: z.number().positive().int()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const Links = z.string().array();
|
||||||
|
|
||||||
|
export type Size = z.infer<typeof Size>;
|
||||||
|
export type Links = z.infer<typeof Links>;
|
||||||
|
|
||||||
|
export const baseGamesTable = pgTable(
|
||||||
|
"base_games",
|
||||||
|
{
|
||||||
|
...timestamps,
|
||||||
|
id: varchar("id", { length: 255 })
|
||||||
|
.primaryKey()
|
||||||
|
.notNull(),
|
||||||
|
links: json("links").$type<Links>(),
|
||||||
|
slug: varchar("slug", { length: 255 })
|
||||||
|
.notNull(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
description: text("description"),
|
||||||
|
releaseDate: utc("release_date").notNull(),
|
||||||
|
size: json("size").$type<Size>().notNull(),
|
||||||
|
primaryGenre: text("primary_genre"),
|
||||||
|
controllerSupport: ControllerEnum("controller_support").notNull(),
|
||||||
|
compatibility: CompatibilityEnum("compatibility").notNull().default("unknown"),
|
||||||
|
// Score ranges from 0.0 to 5.0
|
||||||
|
score: numeric("score", { precision: 2, scale: 1 })
|
||||||
|
.$type<number>()
|
||||||
|
.notNull()
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
unique("idx_base_games_slug").on(table.slug),
|
||||||
|
]
|
||||||
|
)
|
||||||
162
packages/core/src/base-game/index.ts
Normal file
162
packages/core/src/base-game/index.ts
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { fn } from "../utils";
|
||||||
|
import { Common } from "../common";
|
||||||
|
import { Examples } from "../examples";
|
||||||
|
import { createEvent } from "../event";
|
||||||
|
import { eq, isNull, and } from "drizzle-orm";
|
||||||
|
import { ImageTypeEnum } from "../images/images.sql";
|
||||||
|
import { createTransaction, useTransaction } from "../drizzle/transaction";
|
||||||
|
import { CompatibilityEnum, baseGamesTable, Size, ControllerEnum, Links } from "./base-game.sql";
|
||||||
|
|
||||||
|
export namespace BaseGame {
|
||||||
|
export const Info = z.object({
|
||||||
|
id: z.string().openapi({
|
||||||
|
description: Common.IdDescription,
|
||||||
|
example: Examples.BaseGame.id
|
||||||
|
}),
|
||||||
|
slug: z.string().openapi({
|
||||||
|
description: "A URL-friendly unique identifier for the game, used in web addresses and API endpoints",
|
||||||
|
example: Examples.BaseGame.slug
|
||||||
|
}),
|
||||||
|
name: z.string().openapi({
|
||||||
|
description: "The official title of the game as listed on Steam",
|
||||||
|
example: Examples.BaseGame.name
|
||||||
|
}),
|
||||||
|
size: Size.openapi({
|
||||||
|
description: "Storage requirements in bytes: downloadSize represents the compressed download, and sizeOnDisk represents the installed size",
|
||||||
|
example: Examples.BaseGame.size
|
||||||
|
}),
|
||||||
|
releaseDate: z.date().openapi({
|
||||||
|
description: "The initial public release date of the game on Steam",
|
||||||
|
example: Examples.BaseGame.releaseDate
|
||||||
|
}),
|
||||||
|
description: z.string().nullable().openapi({
|
||||||
|
description: "A comprehensive overview of the game, including its features, storyline, and gameplay elements",
|
||||||
|
example: Examples.BaseGame.description
|
||||||
|
}),
|
||||||
|
score: z.number().openapi({
|
||||||
|
description: "The aggregate user review score on Steam, represented as a percentage of positive reviews",
|
||||||
|
example: Examples.BaseGame.score
|
||||||
|
}),
|
||||||
|
links: Links
|
||||||
|
.nullable()
|
||||||
|
.openapi({
|
||||||
|
description: "The social links of this game",
|
||||||
|
example: Examples.BaseGame.links
|
||||||
|
}),
|
||||||
|
primaryGenre: z.string().nullable().openapi({
|
||||||
|
description: "The main category or genre that best represents the game's content and gameplay style",
|
||||||
|
example: Examples.BaseGame.primaryGenre
|
||||||
|
}),
|
||||||
|
controllerSupport: z.enum(ControllerEnum.enumValues).openapi({
|
||||||
|
description: "Indicates the level of gamepad/controller compatibility: 'Full', 'Partial', or 'Unkown' for no support",
|
||||||
|
example: Examples.BaseGame.controllerSupport
|
||||||
|
}),
|
||||||
|
compatibility: z.enum(CompatibilityEnum.enumValues).openapi({
|
||||||
|
description: "Steam Deck/Proton compatibility rating indicating how well the game runs on Linux systems",
|
||||||
|
example: Examples.BaseGame.compatibility
|
||||||
|
}),
|
||||||
|
}).openapi({
|
||||||
|
ref: "BaseGame",
|
||||||
|
description: "Detailed information about a game available in the Nestri library, including technical specifications and metadata",
|
||||||
|
example: Examples.BaseGame
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Info = z.infer<typeof Info>;
|
||||||
|
|
||||||
|
export const Events = {
|
||||||
|
New: createEvent(
|
||||||
|
"new_image.save",
|
||||||
|
z.object({
|
||||||
|
appID: Info.shape.id,
|
||||||
|
url: z.string().url(),
|
||||||
|
type: z.enum(ImageTypeEnum.enumValues)
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
NewBoxArt: createEvent(
|
||||||
|
"new_box_art_image.save",
|
||||||
|
z.object({
|
||||||
|
appID: Info.shape.id,
|
||||||
|
logoUrl: z.string().url(),
|
||||||
|
backgroundUrl: z.string().url(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
NewHeroArt: createEvent(
|
||||||
|
"new_hero_art_image.save",
|
||||||
|
z.object({
|
||||||
|
appID: Info.shape.id,
|
||||||
|
backdropUrl: z.string().url(),
|
||||||
|
screenshots: z.string().url().array(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const create = fn(
|
||||||
|
Info,
|
||||||
|
(input) =>
|
||||||
|
createTransaction(async (tx) => {
|
||||||
|
const result = await tx
|
||||||
|
.select()
|
||||||
|
.from(baseGamesTable)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(baseGamesTable.id, input.id),
|
||||||
|
isNull(baseGamesTable.timeDeleted)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
.execute()
|
||||||
|
.then(rows => rows.at(0))
|
||||||
|
|
||||||
|
if (result) return result.id
|
||||||
|
|
||||||
|
await tx
|
||||||
|
.insert(baseGamesTable)
|
||||||
|
.values(input)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: baseGamesTable.id,
|
||||||
|
set: {
|
||||||
|
timeDeleted: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return input.id
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export const fromID = fn(
|
||||||
|
Info.shape.id,
|
||||||
|
(id) =>
|
||||||
|
useTransaction(async (tx) =>
|
||||||
|
tx
|
||||||
|
.select()
|
||||||
|
.from(baseGamesTable)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(baseGamesTable.id, id),
|
||||||
|
isNull(baseGamesTable.timeDeleted)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
.then(rows => rows.map(serialize).at(0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
export function serialize(
|
||||||
|
input: typeof baseGamesTable.$inferSelect,
|
||||||
|
): z.infer<typeof Info> {
|
||||||
|
return {
|
||||||
|
id: input.id,
|
||||||
|
name: input.name,
|
||||||
|
slug: input.slug,
|
||||||
|
size: input.size,
|
||||||
|
links: input.links,
|
||||||
|
score: input.score,
|
||||||
|
description: input.description,
|
||||||
|
releaseDate: input.releaseDate,
|
||||||
|
primaryGenre: input.primaryGenre,
|
||||||
|
compatibility: input.compatibility,
|
||||||
|
controllerSupport: input.controllerSupport,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
22
packages/core/src/categories/categories.sql.ts
Normal file
22
packages/core/src/categories/categories.sql.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { timestamps } from "../drizzle/types";
|
||||||
|
import { index, pgEnum, pgTable, primaryKey, text, varchar } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
// Intentional grammatical error on category
|
||||||
|
export const CategoryTypeEnum = pgEnum("category_type", ["tag", "genre", "publisher", "developer", "categorie", "franchise"])
|
||||||
|
|
||||||
|
export const categoriesTable = pgTable(
|
||||||
|
"categories",
|
||||||
|
{
|
||||||
|
...timestamps,
|
||||||
|
slug: varchar("slug", { length: 255 })
|
||||||
|
.notNull(),
|
||||||
|
type: CategoryTypeEnum("type").notNull(),
|
||||||
|
name: text("name").notNull(),
|
||||||
|
},
|
||||||
|
(table) => [
|
||||||
|
primaryKey({
|
||||||
|
columns: [table.slug, table.type]
|
||||||
|
}),
|
||||||
|
index("idx_categories_type").on(table.type),
|
||||||
|
]
|
||||||
|
)
|
||||||
128
packages/core/src/categories/index.ts
Normal file
128
packages/core/src/categories/index.ts
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { fn } from "../utils";
|
||||||
|
import { Examples } from "../examples";
|
||||||
|
import { eq, isNull, and } from "drizzle-orm";
|
||||||
|
import { createSelectSchema } from "drizzle-zod";
|
||||||
|
import { categoriesTable } from "./categories.sql";
|
||||||
|
import { createTransaction, useTransaction } from "../drizzle/transaction";
|
||||||
|
|
||||||
|
export namespace Categories {
|
||||||
|
|
||||||
|
const Category = z.object({
|
||||||
|
slug: z.string().openapi({
|
||||||
|
description: "A URL-friendly unique identifier for the category",
|
||||||
|
example: "action-adventure"
|
||||||
|
}),
|
||||||
|
name: z.string().openapi({
|
||||||
|
description: "The human-readable display name of the category",
|
||||||
|
example: "Action Adventure"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Info =
|
||||||
|
z.object({
|
||||||
|
publishers: Category.array().openapi({
|
||||||
|
description: "List of companies or organizations responsible for publishing and distributing the game",
|
||||||
|
example: Examples.Categories.publishers
|
||||||
|
}),
|
||||||
|
developers: Category.array().openapi({
|
||||||
|
description: "List of studios, teams, or individuals who created and developed the game",
|
||||||
|
example: Examples.Categories.developers
|
||||||
|
}),
|
||||||
|
tags: Category.array().openapi({
|
||||||
|
description: "User-defined labels that describe specific features, themes, or characteristics of the game",
|
||||||
|
example: Examples.Categories.tags
|
||||||
|
}),
|
||||||
|
genres: Category.array().openapi({
|
||||||
|
description: "Primary classification categories that define the game's style and type of gameplay",
|
||||||
|
example: Examples.Categories.genres
|
||||||
|
}),
|
||||||
|
categories: Category.array().openapi({
|
||||||
|
description: "Primary classification categories that define the game's categorisation on Steam",
|
||||||
|
example: Examples.Categories.genres
|
||||||
|
}),
|
||||||
|
franchises: Category.array().openapi({
|
||||||
|
description: "The franchise this game belongs belongs to on Steam",
|
||||||
|
example: Examples.Categories.genres
|
||||||
|
}),
|
||||||
|
|
||||||
|
}).openapi({
|
||||||
|
ref: "Categories",
|
||||||
|
description: "A comprehensive categorization system for games, including publishing details, development credits, and content classification",
|
||||||
|
example: Examples.Categories
|
||||||
|
})
|
||||||
|
|
||||||
|
export type Info = z.infer<typeof Info>;
|
||||||
|
|
||||||
|
export const InputInfo = createSelectSchema(categoriesTable)
|
||||||
|
.omit({ timeCreated: true, timeDeleted: true, timeUpdated: true })
|
||||||
|
|
||||||
|
export const create = fn(
|
||||||
|
InputInfo,
|
||||||
|
(input) =>
|
||||||
|
createTransaction(async (tx) => {
|
||||||
|
const result = await tx
|
||||||
|
.select()
|
||||||
|
.from(categoriesTable)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(categoriesTable.slug, input.slug),
|
||||||
|
eq(categoriesTable.type, input.type),
|
||||||
|
isNull(categoriesTable.timeDeleted)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
.execute()
|
||||||
|
.then(rows => rows.at(0))
|
||||||
|
|
||||||
|
if (result) return result.slug
|
||||||
|
|
||||||
|
await tx
|
||||||
|
.insert(categoriesTable)
|
||||||
|
.values(input)
|
||||||
|
.onConflictDoUpdate({
|
||||||
|
target: [categoriesTable.slug, categoriesTable.type],
|
||||||
|
set: { timeDeleted: null }
|
||||||
|
})
|
||||||
|
|
||||||
|
return input.slug
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export const get = fn(
|
||||||
|
InputInfo.pick({ slug: true, type: true }),
|
||||||
|
(input) =>
|
||||||
|
useTransaction((tx) =>
|
||||||
|
tx
|
||||||
|
.select()
|
||||||
|
.from(categoriesTable)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(categoriesTable.slug, input.slug),
|
||||||
|
eq(categoriesTable.type, input.type),
|
||||||
|
isNull(categoriesTable.timeDeleted)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
.execute()
|
||||||
|
.then(rows => serialize(rows))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
export function serialize(
|
||||||
|
input: typeof categoriesTable.$inferSelect[],
|
||||||
|
): z.infer<typeof Info> {
|
||||||
|
return input.reduce<Record<`${typeof categoriesTable.$inferSelect["type"]}s`, { slug: string; name: string }[]>>((acc, cat) => {
|
||||||
|
const key = `${cat.type}s` as `${typeof cat.type}s`
|
||||||
|
acc[key]!.push({ slug: cat.slug, name: cat.name })
|
||||||
|
return acc
|
||||||
|
}, {
|
||||||
|
tags: [],
|
||||||
|
genres: [],
|
||||||
|
publishers: [],
|
||||||
|
developers: [],
|
||||||
|
categories: [],
|
||||||
|
franchises: []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
316
packages/core/src/client/index.ts
Normal file
316
packages/core/src/client/index.ts
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
import type {
|
||||||
|
Shot,
|
||||||
|
AppInfo,
|
||||||
|
ImageInfo,
|
||||||
|
ImageType,
|
||||||
|
SteamAccount,
|
||||||
|
GameTagsResponse,
|
||||||
|
GameDetailsResponse,
|
||||||
|
SteamAppDataResponse,
|
||||||
|
SteamOwnedGamesResponse,
|
||||||
|
SteamPlayerBansResponse,
|
||||||
|
SteamFriendsListResponse,
|
||||||
|
SteamPlayerSummaryResponse,
|
||||||
|
SteamStoreResponse,
|
||||||
|
} from "./types";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { fn } from "../utils";
|
||||||
|
import { Resource } from "sst";
|
||||||
|
import { Steam } from "./steam";
|
||||||
|
import { Utils } from "./utils";
|
||||||
|
import { ImageTypeEnum } from "../images/images.sql";
|
||||||
|
|
||||||
|
export namespace Client {
|
||||||
|
export const getUserLibrary = fn(
|
||||||
|
z.string(),
|
||||||
|
async (steamID) =>
|
||||||
|
await Utils.fetchApi<SteamOwnedGamesResponse>(`https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=${Resource.SteamApiKey.value}&steamid=${steamID}&include_appinfo=1&format=json&include_played_free_games=1&skip_unvetted_apps=0`)
|
||||||
|
)
|
||||||
|
|
||||||
|
export const getFriendsList = fn(
|
||||||
|
z.string(),
|
||||||
|
async (steamID) =>
|
||||||
|
await Utils.fetchApi<SteamFriendsListResponse>(`https://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key=${Resource.SteamApiKey.value}&steamid=${steamID}&relationship=friend`)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const getUserInfo = fn(
|
||||||
|
z.string().array(),
|
||||||
|
async (steamIDs) => {
|
||||||
|
const [userInfo, banInfo, profileInfo] = await Promise.all([
|
||||||
|
Utils.fetchApi<SteamPlayerSummaryResponse>(`https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${Resource.SteamApiKey.value}&steamids=${steamIDs.join(",")}`),
|
||||||
|
Utils.fetchApi<SteamPlayerBansResponse>(`https://api.steampowered.com/ISteamUser/GetPlayerBans/v1/?key=${Resource.SteamApiKey.value}&steamids=${steamIDs.join(",")}`),
|
||||||
|
Utils.fetchProfilesInfo(steamIDs)
|
||||||
|
])
|
||||||
|
|
||||||
|
// Create a map of bans by steamID for fast lookup
|
||||||
|
const bansBySteamID = new Map(
|
||||||
|
banInfo.players.map((b) => [b.SteamId, b])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Map userInfo.players to your desired output using Promise.allSettled
|
||||||
|
// to prevent one error from closing down the whole pipeline
|
||||||
|
const steamAccounts = await Promise.allSettled(
|
||||||
|
userInfo.response.players.map(async (player) => {
|
||||||
|
const ban = bansBySteamID.get(player.steamid);
|
||||||
|
const info = profileInfo.get(player.steamid);
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
throw new Error(`[userInfo] profile info missing for ${player.steamid}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('error' in info) {
|
||||||
|
throw new Error(`error handling profile info for: ${player.steamid}:${info.error}`)
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
id: player.steamid,
|
||||||
|
name: player.personaname,
|
||||||
|
realName: player.realname ?? null,
|
||||||
|
steamMemberSince: new Date(player.timecreated * 1000),
|
||||||
|
avatarHash: player.avatarhash,
|
||||||
|
limitations: {
|
||||||
|
isLimited: info.isLimited,
|
||||||
|
privacyState: info.privacyState,
|
||||||
|
isVacBanned: ban?.VACBanned ?? false,
|
||||||
|
tradeBanState: ban?.EconomyBan ?? "none",
|
||||||
|
visibilityState: player.communityvisibilitystate,
|
||||||
|
},
|
||||||
|
lastSyncedAt: new Date(),
|
||||||
|
profileUrl: player.profileurl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
steamAccounts
|
||||||
|
.filter(result => result.status === 'rejected')
|
||||||
|
.forEach(result => console.warn('[userInfo] failed:', (result as PromiseRejectedResult).reason))
|
||||||
|
|
||||||
|
return steamAccounts.filter(result => result.status === "fulfilled").map(result => (result as PromiseFulfilledResult<SteamAccount>).value)
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getAppInfo = fn(
|
||||||
|
z.string(),
|
||||||
|
async (appid) => {
|
||||||
|
try {
|
||||||
|
const info = await Promise.all([
|
||||||
|
Utils.fetchApi<SteamAppDataResponse>(`https://api.steamcmd.net/v1/info/${appid}`),
|
||||||
|
Utils.fetchApi<SteamStoreResponse>(`https://api.steampowered.com/IStoreBrowseService/GetItems/v1/?key=${Resource.SteamApiKey.value}&input_json={"ids":[{"appid":"${appid}"}],"context":{"language":"english","country_code":"US","steam_realm":"1"},"data_request":{"include_assets":true,"include_release":true,"include_platforms":true,"include_all_purchase_options":true,"include_screenshots":true,"include_trailers":true,"include_ratings":true,"include_tag_count":"40","include_reviews":true,"include_basic_info":true,"include_supported_languages":true,"include_full_description":true,"include_included_items":true,"include_assets_without_overrides":true,"apply_user_filters":true,"include_links":true}}`),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const cmd = info[0].data[appid]
|
||||||
|
const store = info[1].response.store_items[0]
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
throw new Error(`App data not found for appid: ${appid}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!store || store.success !== 1) {
|
||||||
|
throw new Error(`Could not get store information or appid: ${appid}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = store.tagids
|
||||||
|
.map(id => Steam.tags[id.toString() as keyof typeof Steam.tags])
|
||||||
|
.filter((name): name is string => typeof name === 'string')
|
||||||
|
|
||||||
|
const publishers = store.basic_info.publishers
|
||||||
|
.map(i => i.name)
|
||||||
|
|
||||||
|
const developers = store.basic_info.developers
|
||||||
|
.map(i => i.name)
|
||||||
|
|
||||||
|
const franchises = store.basic_info.franchises
|
||||||
|
?.map(i => i.name)
|
||||||
|
|
||||||
|
const genres = cmd?.common.genres &&
|
||||||
|
Object.keys(cmd?.common.genres)
|
||||||
|
.map(id => Steam.genres[id.toString() as keyof typeof Steam.genres])
|
||||||
|
.filter((name): name is string => typeof name === 'string')
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
...(store.categories?.controller_categoryids?.map(i => Steam.categories[i.toString() as keyof typeof Steam.categories]) ?? []),
|
||||||
|
...(store.categories?.supported_player_categoryids?.map(i => Steam.categories[i.toString() as keyof typeof Steam.categories]) ?? [])
|
||||||
|
].filter((name): name is string => typeof name === 'string')
|
||||||
|
|
||||||
|
const assetUrls = Utils.getAssetUrls(cmd?.common.library_assets_full, appid, cmd?.common.header_image.english);
|
||||||
|
|
||||||
|
const screenshots = store.screenshots.all_ages_screenshots?.map(i => `https://shared.cloudflare.steamstatic.com/store_item_assets/${i.filename}`) ?? [];
|
||||||
|
|
||||||
|
const icon = `https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/${appid}/${cmd?.common.icon}.jpg`;
|
||||||
|
|
||||||
|
const data: AppInfo = {
|
||||||
|
id: appid,
|
||||||
|
name: cmd?.common.name.trim(),
|
||||||
|
tags: Utils.createType(tags, "tag"),
|
||||||
|
images: { screenshots, icon, ...assetUrls },
|
||||||
|
size: Utils.getPublicDepotSizes(cmd?.depots!),
|
||||||
|
slug: Utils.createSlug(cmd?.common.name.trim()),
|
||||||
|
publishers: Utils.createType(publishers, "publisher"),
|
||||||
|
developers: Utils.createType(developers, "developer"),
|
||||||
|
categories: Utils.createType(categories, "categorie"),
|
||||||
|
links: store.links ? store.links.map(i => i.url) : null,
|
||||||
|
genres: genres ? Utils.createType(genres, "genre") : [],
|
||||||
|
franchises: franchises ? Utils.createType(franchises, "franchise") : [],
|
||||||
|
description: store.basic_info.short_description ? Utils.cleanDescription(store.basic_info.short_description) : null,
|
||||||
|
controllerSupport: cmd?.common.controller_support ?? "unknown" as any,
|
||||||
|
releaseDate: new Date(Number(cmd?.common.steam_release_date) * 1000),
|
||||||
|
primaryGenre: !!cmd?.common.primary_genre && Steam.genres[cmd?.common.primary_genre as keyof typeof Steam.genres] ? Steam.genres[cmd?.common.primary_genre as keyof typeof Steam.genres] : null,
|
||||||
|
compatibility: store?.platforms.steam_os_compat_category ? Utils.compatibilityType(store?.platforms.steam_os_compat_category.toString() as any).toLowerCase() : "unknown" as any,
|
||||||
|
score: Utils.estimateRatingFromSummary(store.reviews.summary_filtered.review_count, store.reviews.summary_filtered.percent_positive)
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`Error handling: ${appid}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const getImageUrls = fn(
|
||||||
|
z.string(),
|
||||||
|
async (appid) => {
|
||||||
|
const [appData, details] = await Promise.all([
|
||||||
|
Utils.fetchApi<SteamAppDataResponse>(`https://api.steamcmd.net/v1/info/${appid}`),
|
||||||
|
Utils.fetchApi<GameDetailsResponse>(
|
||||||
|
`https://store.steampowered.com/apphover/${appid}?full=1&review_score_preference=1&pagev6=true&json=1`
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const game = appData.data[appid]?.common;
|
||||||
|
if (!game) throw new Error('Game info missing');
|
||||||
|
|
||||||
|
// 2. Prepare URLs
|
||||||
|
const screenshots = Utils.getScreenshotUrls(details.rgScreenshots || []);
|
||||||
|
const assetUrls = Utils.getAssetUrls(game.library_assets_full, appid, game.header_image.english);
|
||||||
|
const icon = `https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/${appid}/${game.icon}.jpg`;
|
||||||
|
|
||||||
|
return { screenshots, icon, ...assetUrls }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const getImageInfo = fn(
|
||||||
|
z.object({
|
||||||
|
type: z.enum(ImageTypeEnum.enumValues),
|
||||||
|
url: z.string()
|
||||||
|
}),
|
||||||
|
async (input) =>
|
||||||
|
Utils.fetchBuffer(input.url)
|
||||||
|
.then(buf => Utils.getImageMetadata(buf))
|
||||||
|
.then(meta => ({ ...meta, position: 0, sourceUrl: input.url, type: input.type } as ImageInfo))
|
||||||
|
)
|
||||||
|
|
||||||
|
export const createBoxArt = fn(
|
||||||
|
z.object({
|
||||||
|
backgroundUrl: z.string(),
|
||||||
|
logoUrl: z.string(),
|
||||||
|
}),
|
||||||
|
async (input) =>
|
||||||
|
Utils.createBoxArtBuffer(input.logoUrl, input.backgroundUrl)
|
||||||
|
.then(buf => Utils.getImageMetadata(buf))
|
||||||
|
.then(meta => ({ ...meta, position: 0, sourceUrl: null, type: 'boxArt' as const }) as ImageInfo)
|
||||||
|
)
|
||||||
|
|
||||||
|
export const createHeroArt = fn(
|
||||||
|
z.object({
|
||||||
|
screenshots: z.string().array(),
|
||||||
|
backdropUrl: z.string()
|
||||||
|
}),
|
||||||
|
async (input) => {
|
||||||
|
// Download screenshot buffers in parallel
|
||||||
|
const shots: Shot[] = await Promise.all(
|
||||||
|
input.screenshots.map(async url => ({ url, buffer: await Utils.fetchBuffer(url) }))
|
||||||
|
);
|
||||||
|
|
||||||
|
const baselineBuffer = await Utils.fetchBuffer(input.backdropUrl);
|
||||||
|
|
||||||
|
// 4. Score screenshots (or pick single)
|
||||||
|
const scores =
|
||||||
|
shots.length === 1
|
||||||
|
? [{ url: shots[0].url, score: 0 }]
|
||||||
|
: (await Utils.rankScreenshots(baselineBuffer, shots, {
|
||||||
|
threshold: 0.08,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Build url->rank map
|
||||||
|
const rankMap = new Map<string, number>();
|
||||||
|
scores.forEach((s, i) => rankMap.set(s.url, i));
|
||||||
|
|
||||||
|
// 5. Create tasks for all images
|
||||||
|
const tasks: Array<Promise<ImageInfo>> = [];
|
||||||
|
|
||||||
|
// 5a. Screenshots and heroArt metadata (top 4)
|
||||||
|
for (const { url, buffer } of shots) {
|
||||||
|
const rank = rankMap.get(url);
|
||||||
|
if (rank === undefined || rank >= 4) continue;
|
||||||
|
const type: ImageType = rank === 0 ? 'heroArt' : 'screenshot';
|
||||||
|
tasks.push(
|
||||||
|
Utils.getImageMetadata(buffer).then(meta => ({ ...meta, sourceUrl: url, position: type == "screenshot" ? rank - 1 : rank, type } as ImageInfo))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const settled = await Promise.allSettled(tasks);
|
||||||
|
|
||||||
|
settled
|
||||||
|
.filter(r => r.status === "rejected")
|
||||||
|
.forEach(r => console.warn("[getHeroArt] failed:", (r as PromiseRejectedResult).reason));
|
||||||
|
|
||||||
|
// Await all and return
|
||||||
|
return settled.filter(s => s.status === "fulfilled").map(r => (r as PromiseFulfilledResult<ImageInfo>).value)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies a Steam OpenID response by sending a request back to Steam
|
||||||
|
* with mode=check_authentication
|
||||||
|
*/
|
||||||
|
export async function verifyOpenIDResponse(params: URLSearchParams): Promise<string | null> {
|
||||||
|
try {
|
||||||
|
// Create a new URLSearchParams with all the original parameters
|
||||||
|
const verificationParams = new URLSearchParams();
|
||||||
|
|
||||||
|
// Copy all parameters from the original request
|
||||||
|
for (const [key, value] of params.entries()) {
|
||||||
|
verificationParams.append(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change mode to check_authentication for verification
|
||||||
|
verificationParams.set('openid.mode', 'check_authentication');
|
||||||
|
|
||||||
|
// Send verification request to Steam
|
||||||
|
const verificationResponse = await fetch('https://steamcommunity.com/openid/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: verificationParams.toString()
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseText = await verificationResponse.text();
|
||||||
|
|
||||||
|
// Check if verification was successful
|
||||||
|
if (!responseText.includes('is_valid:true')) {
|
||||||
|
console.error('OpenID verification failed: Invalid response from Steam', responseText);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract steamID from the claimed_id
|
||||||
|
const claimedId = params.get('openid.claimed_id');
|
||||||
|
if (!claimedId) {
|
||||||
|
console.error('OpenID verification failed: Missing claimed_id');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the Steam ID from the claimed_id
|
||||||
|
const steamID = claimedId.split('/').pop();
|
||||||
|
if (!steamID || !/^\d+$/.test(steamID)) {
|
||||||
|
console.error('OpenID verification failed: Invalid steamID format', steamID);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return steamID;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('OpenID verification error:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
544
packages/core/src/client/steam.ts
Normal file
544
packages/core/src/client/steam.ts
Normal file
@@ -0,0 +1,544 @@
|
|||||||
|
export namespace Steam {
|
||||||
|
//Source: https://github.com/woctezuma/steam-api/blob/master/data/genres.json
|
||||||
|
export const genres = {
|
||||||
|
"1": "Action",
|
||||||
|
"2": "Strategy",
|
||||||
|
"3": "RPG",
|
||||||
|
"4": "Casual",
|
||||||
|
"9": "Racing",
|
||||||
|
"18": "Sports",
|
||||||
|
"23": "Indie",
|
||||||
|
"25": "Adventure",
|
||||||
|
"28": "Simulation",
|
||||||
|
"29": "Massively Multiplayer",
|
||||||
|
"37": "Free to Play",
|
||||||
|
"50": "Accounting",
|
||||||
|
"51": "Animation & Modeling",
|
||||||
|
"52": "Audio Production",
|
||||||
|
"53": "Design & Illustration",
|
||||||
|
"54": "Education",
|
||||||
|
"55": "Photo Editing",
|
||||||
|
"56": "Software Training",
|
||||||
|
"57": "Utilities",
|
||||||
|
"58": "Video Production",
|
||||||
|
"59": "Web Publishing",
|
||||||
|
"60": "Game Development",
|
||||||
|
"70": "Early Access",
|
||||||
|
"71": "Sexual Content",
|
||||||
|
"72": "Nudity",
|
||||||
|
"73": "Violent",
|
||||||
|
"74": "Gore",
|
||||||
|
"80": "Movie",
|
||||||
|
"81": "Documentary",
|
||||||
|
"82": "Episodic",
|
||||||
|
"83": "Short",
|
||||||
|
"84": "Tutorial",
|
||||||
|
"85": "360 Video"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Source: https://github.com/woctezuma/steam-api/blob/master/data/categories.json
|
||||||
|
export const categories = {
|
||||||
|
"1": "Multi-player",
|
||||||
|
"2": "Single-player",
|
||||||
|
"6": "Mods (require HL2)",
|
||||||
|
"7": "Mods (require HL1)",
|
||||||
|
"8": "Valve Anti-Cheat enabled",
|
||||||
|
"9": "Co-op",
|
||||||
|
"10": "Demos",
|
||||||
|
"12": "HDR available",
|
||||||
|
"13": "Captions available",
|
||||||
|
"14": "Commentary available",
|
||||||
|
"15": "Stats",
|
||||||
|
"16": "Includes Source SDK",
|
||||||
|
"17": "Includes level editor",
|
||||||
|
"18": "Partial Controller Support",
|
||||||
|
"19": "Mods",
|
||||||
|
"20": "MMO",
|
||||||
|
"21": "Downloadable Content",
|
||||||
|
"22": "Steam Achievements",
|
||||||
|
"23": "Steam Cloud",
|
||||||
|
"24": "Shared/Split Screen",
|
||||||
|
"25": "Steam Leaderboards",
|
||||||
|
"27": "Cross-Platform Multiplayer",
|
||||||
|
"28": "Full controller support",
|
||||||
|
"29": "Steam Trading Cards",
|
||||||
|
"30": "Steam Workshop",
|
||||||
|
"31": "VR Support",
|
||||||
|
"32": "Steam Turn Notifications",
|
||||||
|
"33": "Native Steam Controller",
|
||||||
|
"35": "In-App Purchases",
|
||||||
|
"36": "Online PvP",
|
||||||
|
"37": "Shared/Split Screen PvP",
|
||||||
|
"38": "Online Co-op",
|
||||||
|
"39": "Shared/Split Screen Co-op",
|
||||||
|
"40": "SteamVR Collectibles",
|
||||||
|
"41": "Remote Play on Phone",
|
||||||
|
"42": "Remote Play on Tablet",
|
||||||
|
"43": "Remote Play on TV",
|
||||||
|
"44": "Remote Play Together",
|
||||||
|
"45": "Cloud Gaming",
|
||||||
|
"46": "Cloud Gaming (NVIDIA)",
|
||||||
|
"47": "LAN PvP",
|
||||||
|
"48": "LAN Co-op",
|
||||||
|
"49": "PvP",
|
||||||
|
"50": "Additional High-Quality Audio",
|
||||||
|
"51": "Steam Workshop",
|
||||||
|
"52": "Tracked Controller Support",
|
||||||
|
"53": "VR Supported",
|
||||||
|
"54": "VR Only"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Source: https://files.catbox.moe/96bty7.json
|
||||||
|
export const tags = {
|
||||||
|
"9": "Strategy",
|
||||||
|
"19": "Action",
|
||||||
|
"21": "Adventure",
|
||||||
|
"84": "Design & Illustration",
|
||||||
|
"87": "Utilities",
|
||||||
|
"113": "Free to Play",
|
||||||
|
"122": "RPG",
|
||||||
|
"128": "Massively Multiplayer",
|
||||||
|
"492": "Indie",
|
||||||
|
"493": "Early Access",
|
||||||
|
"597": "Casual",
|
||||||
|
"599": "Simulation",
|
||||||
|
"699": "Racing",
|
||||||
|
"701": "Sports",
|
||||||
|
"784": "Video Production",
|
||||||
|
"809": "Photo Editing",
|
||||||
|
"872": "Animation & Modeling",
|
||||||
|
"1027": "Audio Production",
|
||||||
|
"1036": "Education",
|
||||||
|
"1038": "Web Publishing",
|
||||||
|
"1445": "Software Training",
|
||||||
|
"1616": "Trains",
|
||||||
|
"1621": "Music",
|
||||||
|
"1625": "Platformer",
|
||||||
|
"1628": "Metroidvania",
|
||||||
|
"1638": "Dog",
|
||||||
|
"1643": "Building",
|
||||||
|
"1644": "Driving",
|
||||||
|
"1645": "Tower Defense",
|
||||||
|
"1646": "Hack and Slash",
|
||||||
|
"1647": "Western",
|
||||||
|
"1649": "GameMaker",
|
||||||
|
"1651": "Satire",
|
||||||
|
"1654": "Relaxing",
|
||||||
|
"1659": "Zombies",
|
||||||
|
"1662": "Survival",
|
||||||
|
"1663": "FPS",
|
||||||
|
"1664": "Puzzle",
|
||||||
|
"1665": "Match 3",
|
||||||
|
"1666": "Card Game",
|
||||||
|
"1667": "Horror",
|
||||||
|
"1669": "Moddable",
|
||||||
|
"1670": "4X",
|
||||||
|
"1671": "Superhero",
|
||||||
|
"1673": "Aliens",
|
||||||
|
"1674": "Typing",
|
||||||
|
"1676": "RTS",
|
||||||
|
"1677": "Turn-Based",
|
||||||
|
"1678": "War",
|
||||||
|
"1680": "Heist",
|
||||||
|
"1681": "Pirates",
|
||||||
|
"1684": "Fantasy",
|
||||||
|
"1685": "Co-op",
|
||||||
|
"1687": "Stealth",
|
||||||
|
"1688": "Ninja",
|
||||||
|
"1693": "Classic",
|
||||||
|
"1695": "Open World",
|
||||||
|
"1697": "Third Person",
|
||||||
|
"1698": "Point & Click",
|
||||||
|
"1702": "Crafting",
|
||||||
|
"1708": "Tactical",
|
||||||
|
"1710": "Surreal",
|
||||||
|
"1714": "Psychedelic",
|
||||||
|
"1716": "Roguelike",
|
||||||
|
"1717": "Hex Grid",
|
||||||
|
"1718": "MOBA",
|
||||||
|
"1719": "Comedy",
|
||||||
|
"1720": "Dungeon Crawler",
|
||||||
|
"1721": "Psychological Horror",
|
||||||
|
"1723": "Action RTS",
|
||||||
|
"1730": "Sokoban",
|
||||||
|
"1732": "Voxel",
|
||||||
|
"1733": "Unforgiving",
|
||||||
|
"1734": "Fast-Paced",
|
||||||
|
"1736": "LEGO",
|
||||||
|
"1738": "Hidden Object",
|
||||||
|
"1741": "Turn-Based Strategy",
|
||||||
|
"1742": "Story Rich",
|
||||||
|
"1743": "Fighting",
|
||||||
|
"1746": "Basketball",
|
||||||
|
"1751": "Comic Book",
|
||||||
|
"1752": "Rhythm",
|
||||||
|
"1753": "Skateboarding",
|
||||||
|
"1754": "MMORPG",
|
||||||
|
"1755": "Space",
|
||||||
|
"1756": "Great Soundtrack",
|
||||||
|
"1759": "Perma Death",
|
||||||
|
"1770": "Board Game",
|
||||||
|
"1773": "Arcade",
|
||||||
|
"1774": "Shooter",
|
||||||
|
"1775": "PvP",
|
||||||
|
"1777": "Steampunk",
|
||||||
|
"3796": "Based On A Novel",
|
||||||
|
"3798": "Side Scroller",
|
||||||
|
"3799": "Visual Novel",
|
||||||
|
"3810": "Sandbox",
|
||||||
|
"3813": "Real Time Tactics",
|
||||||
|
"3814": "Third-Person Shooter",
|
||||||
|
"3834": "Exploration",
|
||||||
|
"3835": "Post-apocalyptic",
|
||||||
|
"3839": "First-Person",
|
||||||
|
"3841": "Local Co-Op",
|
||||||
|
"3843": "Online Co-Op",
|
||||||
|
"3854": "Lore-Rich",
|
||||||
|
"3859": "Multiplayer",
|
||||||
|
"3871": "2D",
|
||||||
|
"3877": "Precision Platformer",
|
||||||
|
"3878": "Competitive",
|
||||||
|
"3916": "Old School",
|
||||||
|
"3920": "Cooking",
|
||||||
|
"3934": "Immersive",
|
||||||
|
"3942": "Sci-fi",
|
||||||
|
"3952": "Gothic",
|
||||||
|
"3955": "Character Action Game",
|
||||||
|
"3959": "Roguelite",
|
||||||
|
"3964": "Pixel Graphics",
|
||||||
|
"3965": "Epic",
|
||||||
|
"3968": "Physics",
|
||||||
|
"3978": "Survival Horror",
|
||||||
|
"3987": "Historical",
|
||||||
|
"3993": "Combat",
|
||||||
|
"4004": "Retro",
|
||||||
|
"4018": "Vampire",
|
||||||
|
"4026": "Difficult",
|
||||||
|
"4036": "Parkour",
|
||||||
|
"4046": "Dragons",
|
||||||
|
"4057": "Magic",
|
||||||
|
"4064": "Thriller",
|
||||||
|
"4085": "Anime",
|
||||||
|
"4094": "Minimalist",
|
||||||
|
"4102": "Combat Racing",
|
||||||
|
"4106": "Action-Adventure",
|
||||||
|
"4115": "Cyberpunk",
|
||||||
|
"4136": "Funny",
|
||||||
|
"4137": "Transhumanism",
|
||||||
|
"4145": "Cinematic",
|
||||||
|
"4150": "World War II",
|
||||||
|
"4155": "Class-Based",
|
||||||
|
"4158": "Beat 'em up",
|
||||||
|
"4161": "Real-Time",
|
||||||
|
"4166": "Atmospheric",
|
||||||
|
"4168": "Military",
|
||||||
|
"4172": "Medieval",
|
||||||
|
"4175": "Realistic",
|
||||||
|
"4182": "Singleplayer",
|
||||||
|
"4184": "Chess",
|
||||||
|
"4190": "Addictive",
|
||||||
|
"4191": "3D",
|
||||||
|
"4195": "Cartoony",
|
||||||
|
"4202": "Trading",
|
||||||
|
"4231": "Action RPG",
|
||||||
|
"4234": "Short",
|
||||||
|
"4236": "Loot",
|
||||||
|
"4242": "Episodic",
|
||||||
|
"4252": "Stylized",
|
||||||
|
"4255": "Shoot 'Em Up",
|
||||||
|
"4291": "Spaceships",
|
||||||
|
"4295": "Futuristic",
|
||||||
|
"4305": "Colorful",
|
||||||
|
"4325": "Turn-Based Combat",
|
||||||
|
"4328": "City Builder",
|
||||||
|
"4342": "Dark",
|
||||||
|
"4345": "Gore",
|
||||||
|
"4364": "Grand Strategy",
|
||||||
|
"4376": "Assassin",
|
||||||
|
"4400": "Abstract",
|
||||||
|
"4434": "JRPG",
|
||||||
|
"4474": "CRPG",
|
||||||
|
"4486": "Choose Your Own Adventure",
|
||||||
|
"4508": "Co-op Campaign",
|
||||||
|
"4520": "Farming",
|
||||||
|
"4559": "Quick-Time Events",
|
||||||
|
"4562": "Cartoon",
|
||||||
|
"4598": "Alternate History",
|
||||||
|
"4604": "Dark Fantasy",
|
||||||
|
"4608": "Swordplay",
|
||||||
|
"4637": "Top-Down Shooter",
|
||||||
|
"4667": "Violent",
|
||||||
|
"4684": "Wargame",
|
||||||
|
"4695": "Economy",
|
||||||
|
"4700": "Movie",
|
||||||
|
"4711": "Replay Value",
|
||||||
|
"4726": "Cute",
|
||||||
|
"4736": "2D Fighter",
|
||||||
|
"4747": "Character Customization",
|
||||||
|
"4754": "Politics",
|
||||||
|
"4758": "Twin Stick Shooter",
|
||||||
|
"4777": "Spectacle fighter",
|
||||||
|
"4791": "Top-Down",
|
||||||
|
"4821": "Mechs",
|
||||||
|
"4835": "6DOF",
|
||||||
|
"4840": "4 Player Local",
|
||||||
|
"4845": "Capitalism",
|
||||||
|
"4853": "Political",
|
||||||
|
"4878": "Parody",
|
||||||
|
"4885": "Bullet Hell",
|
||||||
|
"4947": "Romance",
|
||||||
|
"4975": "2.5D",
|
||||||
|
"4994": "Naval Combat",
|
||||||
|
"5030": "Dystopian",
|
||||||
|
"5055": "eSports",
|
||||||
|
"5094": "Narration",
|
||||||
|
"5125": "Procedural Generation",
|
||||||
|
"5153": "Kickstarter",
|
||||||
|
"5154": "Score Attack",
|
||||||
|
"5160": "Dinosaurs",
|
||||||
|
"5179": "Cold War",
|
||||||
|
"5186": "Psychological",
|
||||||
|
"5228": "Blood",
|
||||||
|
"5230": "Sequel",
|
||||||
|
"5300": "God Game",
|
||||||
|
"5310": "Games Workshop",
|
||||||
|
"5348": "Mod",
|
||||||
|
"5350": "Family Friendly",
|
||||||
|
"5363": "Destruction",
|
||||||
|
"5372": "Conspiracy",
|
||||||
|
"5379": "2D Platformer",
|
||||||
|
"5382": "World War I",
|
||||||
|
"5390": "Time Attack",
|
||||||
|
"5395": "3D Platformer",
|
||||||
|
"5407": "Benchmark",
|
||||||
|
"5411": "Beautiful",
|
||||||
|
"5432": "Programming",
|
||||||
|
"5502": "Hacking",
|
||||||
|
"5537": "Puzzle Platformer",
|
||||||
|
"5547": "Arena Shooter",
|
||||||
|
"5577": "RPGMaker",
|
||||||
|
"5608": "Emotional",
|
||||||
|
"5611": "Mature",
|
||||||
|
"5613": "Detective",
|
||||||
|
"5652": "Collectathon",
|
||||||
|
"5673": "Modern",
|
||||||
|
"5708": "Remake",
|
||||||
|
"5711": "Team-Based",
|
||||||
|
"5716": "Mystery",
|
||||||
|
"5727": "Baseball",
|
||||||
|
"5752": "Robots",
|
||||||
|
"5765": "Gun Customization",
|
||||||
|
"5794": "Science",
|
||||||
|
"5796": "Bullet Time",
|
||||||
|
"5851": "Isometric",
|
||||||
|
"5900": "Walking Simulator",
|
||||||
|
"5914": "Tennis",
|
||||||
|
"5923": "Dark Humor",
|
||||||
|
"5941": "Reboot",
|
||||||
|
"5981": "Mining",
|
||||||
|
"5984": "Drama",
|
||||||
|
"6041": "Horses",
|
||||||
|
"6052": "Noir",
|
||||||
|
"6129": "Logic",
|
||||||
|
"6214": "Birds",
|
||||||
|
"6276": "Inventory Management",
|
||||||
|
"6310": "Diplomacy",
|
||||||
|
"6378": "Crime",
|
||||||
|
"6426": "Choices Matter",
|
||||||
|
"6506": "3D Fighter",
|
||||||
|
"6621": "Pinball",
|
||||||
|
"6625": "Time Manipulation",
|
||||||
|
"6650": "Nudity",
|
||||||
|
"6691": "1990's",
|
||||||
|
"6702": "Mars",
|
||||||
|
"6730": "PvE",
|
||||||
|
"6815": "Hand-drawn",
|
||||||
|
"6869": "Nonlinear",
|
||||||
|
"6910": "Naval",
|
||||||
|
"6915": "Martial Arts",
|
||||||
|
"6948": "Rome",
|
||||||
|
"6971": "Multiple Endings",
|
||||||
|
"7038": "Golf",
|
||||||
|
"7107": "Real-Time with Pause",
|
||||||
|
"7108": "Party",
|
||||||
|
"7113": "Crowdfunded",
|
||||||
|
"7178": "Party Game",
|
||||||
|
"7208": "Female Protagonist",
|
||||||
|
"7250": "Linear",
|
||||||
|
"7309": "Skiing",
|
||||||
|
"7328": "Bowling",
|
||||||
|
"7332": "Base Building",
|
||||||
|
"7368": "Local Multiplayer",
|
||||||
|
"7423": "Sniper",
|
||||||
|
"7432": "Lovecraftian",
|
||||||
|
"7478": "Illuminati",
|
||||||
|
"7481": "Controller",
|
||||||
|
"7556": "Dice",
|
||||||
|
"7569": "Grid-Based Movement",
|
||||||
|
"7622": "Offroad",
|
||||||
|
"7702": "Narrative",
|
||||||
|
"7743": "1980s",
|
||||||
|
"7782": "Cult Classic",
|
||||||
|
"7918": "Dwarf",
|
||||||
|
"7926": "Artificial Intelligence",
|
||||||
|
"7948": "Soundtrack",
|
||||||
|
"8013": "Software",
|
||||||
|
"8075": "TrackIR",
|
||||||
|
"8093": "Minigames",
|
||||||
|
"8122": "Level Editor",
|
||||||
|
"8253": "Music-Based Procedural Generation",
|
||||||
|
"8369": "Investigation",
|
||||||
|
"8461": "Well-Written",
|
||||||
|
"8666": "Runner",
|
||||||
|
"8945": "Resource Management",
|
||||||
|
"9130": "Hentai",
|
||||||
|
"9157": "Underwater",
|
||||||
|
"9204": "Immersive Sim",
|
||||||
|
"9271": "Trading Card Game",
|
||||||
|
"9541": "Demons",
|
||||||
|
"9551": "Dating Sim",
|
||||||
|
"9564": "Hunting",
|
||||||
|
"9592": "Dynamic Narration",
|
||||||
|
"9803": "Snow",
|
||||||
|
"9994": "Experience",
|
||||||
|
"10235": "Life Sim",
|
||||||
|
"10383": "Transportation",
|
||||||
|
"10397": "Memes",
|
||||||
|
"10437": "Trivia",
|
||||||
|
"10679": "Time Travel",
|
||||||
|
"10695": "Party-Based RPG",
|
||||||
|
"10808": "Supernatural",
|
||||||
|
"10816": "Split Screen",
|
||||||
|
"11014": "Interactive Fiction",
|
||||||
|
"11095": "Boss Rush",
|
||||||
|
"11104": "Vehicular Combat",
|
||||||
|
"11123": "Mouse only",
|
||||||
|
"11333": "Villain Protagonist",
|
||||||
|
"11634": "Vikings",
|
||||||
|
"12057": "Tutorial",
|
||||||
|
"12095": "Sexual Content",
|
||||||
|
"12190": "Boxing",
|
||||||
|
"12286": "Warhammer 40K",
|
||||||
|
"12472": "Management",
|
||||||
|
"13070": "Solitaire",
|
||||||
|
"13190": "America",
|
||||||
|
"13276": "Tanks",
|
||||||
|
"13382": "Archery",
|
||||||
|
"13577": "Sailing",
|
||||||
|
"13782": "Experimental",
|
||||||
|
"13906": "Game Development",
|
||||||
|
"14139": "Turn-Based Tactics",
|
||||||
|
"14153": "Dungeons & Dragons",
|
||||||
|
"14720": "Nostalgia",
|
||||||
|
"14906": "Intentionally Awkward Controls",
|
||||||
|
"15045": "Flight",
|
||||||
|
"15172": "Conversation",
|
||||||
|
"15277": "Philosophical",
|
||||||
|
"15339": "Documentary",
|
||||||
|
"15564": "Fishing",
|
||||||
|
"15868": "Motocross",
|
||||||
|
"15954": "Silent Protagonist",
|
||||||
|
"16094": "Mythology",
|
||||||
|
"16250": "Gambling",
|
||||||
|
"16598": "Space Sim",
|
||||||
|
"16689": "Time Management",
|
||||||
|
"17015": "Werewolves",
|
||||||
|
"17305": "Strategy RPG",
|
||||||
|
"17337": "Lemmings",
|
||||||
|
"17389": "Tabletop",
|
||||||
|
"17770": "Asynchronous Multiplayer",
|
||||||
|
"17894": "Cats",
|
||||||
|
"17927": "Pool",
|
||||||
|
"18594": "FMV",
|
||||||
|
"19568": "Cycling",
|
||||||
|
"19780": "Submarine",
|
||||||
|
"19995": "Dark Comedy",
|
||||||
|
"21006": "Underground",
|
||||||
|
"21491": "Demo Available",
|
||||||
|
"21725": "Tactical RPG",
|
||||||
|
"21978": "VR",
|
||||||
|
"22602": "Agriculture",
|
||||||
|
"22955": "Mini Golf",
|
||||||
|
"24003": "Word Game",
|
||||||
|
"24904": "NSFW",
|
||||||
|
"25085": "Touch-Friendly",
|
||||||
|
"26921": "Political Sim",
|
||||||
|
"27758": "Voice Control",
|
||||||
|
"28444": "Snowboarding",
|
||||||
|
"29363": "3D Vision",
|
||||||
|
"29482": "Souls-like",
|
||||||
|
"29855": "Ambient",
|
||||||
|
"30358": "Nature",
|
||||||
|
"30927": "Fox",
|
||||||
|
"31275": "Text-Based",
|
||||||
|
"31579": "Otome",
|
||||||
|
"32322": "Deckbuilding",
|
||||||
|
"33572": "Mahjong",
|
||||||
|
"35079": "Job Simulator",
|
||||||
|
"42089": "Jump Scare",
|
||||||
|
"42329": "Coding",
|
||||||
|
"42804": "Action Roguelike",
|
||||||
|
"44868": "LGBTQ+",
|
||||||
|
"47827": "Wrestling",
|
||||||
|
"49213": "Rugby",
|
||||||
|
"51306": "Foreign",
|
||||||
|
"56690": "On-Rails Shooter",
|
||||||
|
"61357": "Electronic Music",
|
||||||
|
"65443": "Adult Content",
|
||||||
|
"71389": "Spelling",
|
||||||
|
"87918": "Farming Sim",
|
||||||
|
"91114": "Shop Keeper",
|
||||||
|
"92092": "Jet",
|
||||||
|
"96359": "Skating",
|
||||||
|
"97376": "Cozy",
|
||||||
|
"102530": "Elf",
|
||||||
|
"117648": "8-bit Music",
|
||||||
|
"123332": "Bikes",
|
||||||
|
"129761": "ATV",
|
||||||
|
"143739": "Electronic",
|
||||||
|
"150626": "Gaming",
|
||||||
|
"158638": "Cricket",
|
||||||
|
"176981": "Battle Royale",
|
||||||
|
"180368": "Faith",
|
||||||
|
"189941": "Instrumental Music",
|
||||||
|
"198631": "Mystery Dungeon",
|
||||||
|
"198913": "Motorbike",
|
||||||
|
"220585": "Colony Sim",
|
||||||
|
"233824": "Feature Film",
|
||||||
|
"252854": "BMX",
|
||||||
|
"255534": "Automation",
|
||||||
|
"323922": "Musou",
|
||||||
|
"324176": "Hockey",
|
||||||
|
"337964": "Rock Music",
|
||||||
|
"348922": "Steam Machine",
|
||||||
|
"353880": "Looter Shooter",
|
||||||
|
"363767": "Snooker",
|
||||||
|
"379975": "Clicker",
|
||||||
|
"454187": "Traditional Roguelike",
|
||||||
|
"552282": "Wholesome",
|
||||||
|
"603297": "Hardware",
|
||||||
|
"615955": "Idler",
|
||||||
|
"620519": "Hero Shooter",
|
||||||
|
"745697": "Social Deduction",
|
||||||
|
"769306": "Escape Room",
|
||||||
|
"776177": "360 Video",
|
||||||
|
"791774": "Card Battler",
|
||||||
|
"847164": "Volleyball",
|
||||||
|
"856791": "Asymmetric VR",
|
||||||
|
"916648": "Creature Collector",
|
||||||
|
"922563": "Roguevania",
|
||||||
|
"1003823": "Profile Features Limited",
|
||||||
|
"1023537": "Boomer Shooter",
|
||||||
|
"1084988": "Auto Battler",
|
||||||
|
"1091588": "Roguelike Deckbuilder",
|
||||||
|
"1100686": "Outbreak Sim",
|
||||||
|
"1100687": "Automobile Sim",
|
||||||
|
"1100688": "Medical Sim",
|
||||||
|
"1100689": "Open World Survival Craft",
|
||||||
|
"1199779": "Extraction Shooter",
|
||||||
|
"1220528": "Hobby Sim",
|
||||||
|
"1254546": "Football (Soccer)",
|
||||||
|
"1254552": "Football (American)",
|
||||||
|
"1368160": "AI Content Disclosed",
|
||||||
|
}
|
||||||
|
}
|
||||||
600
packages/core/src/client/types.ts
Normal file
600
packages/core/src/client/types.ts
Normal file
@@ -0,0 +1,600 @@
|
|||||||
|
export interface SteamApp {
|
||||||
|
/** Steam application ID */
|
||||||
|
appid: number;
|
||||||
|
|
||||||
|
/** Array of Steam IDs that own this app */
|
||||||
|
owner_steamids: string[];
|
||||||
|
|
||||||
|
/** Name of the game/application */
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/** Filename of the game's capsule image */
|
||||||
|
capsule_filename: string;
|
||||||
|
|
||||||
|
/** Hash value for the game's icon */
|
||||||
|
img_icon_hash: string;
|
||||||
|
|
||||||
|
/** Reason code for exclusion (0 indicates no exclusion) */
|
||||||
|
exclude_reason: number;
|
||||||
|
|
||||||
|
/** Unix timestamp when the app was acquired */
|
||||||
|
rt_time_acquired: number;
|
||||||
|
|
||||||
|
/** Unix timestamp when the app was last played */
|
||||||
|
rt_last_played: number;
|
||||||
|
|
||||||
|
/** Total playtime in seconds */
|
||||||
|
rt_playtime: number;
|
||||||
|
|
||||||
|
/** Type identifier for the app (1 = game) */
|
||||||
|
app_type: number;
|
||||||
|
|
||||||
|
/** Array of content descriptor IDs */
|
||||||
|
content_descriptors?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamApiResponse {
|
||||||
|
response: {
|
||||||
|
apps: SteamApp[];
|
||||||
|
owner_steamid: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamAppDataResponse {
|
||||||
|
data: Record<string, SteamAppEntry>;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamAppEntry {
|
||||||
|
_change_number: number;
|
||||||
|
_missing_token: boolean;
|
||||||
|
_sha: string;
|
||||||
|
_size: number;
|
||||||
|
appid: string;
|
||||||
|
common: CommonData;
|
||||||
|
config: AppConfig;
|
||||||
|
depots: AppDepots;
|
||||||
|
extended: AppExtended;
|
||||||
|
ufs: UFSData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommonData {
|
||||||
|
associations: Record<string, { name: string; type: string }>;
|
||||||
|
category: Record<string, string>;
|
||||||
|
clienticon: string;
|
||||||
|
clienttga: string;
|
||||||
|
community_hub_visible: string;
|
||||||
|
community_visible_stats: string;
|
||||||
|
content_descriptors: Record<string, string>;
|
||||||
|
controller_support?: string;
|
||||||
|
controllertagwizard: string;
|
||||||
|
gameid: string;
|
||||||
|
genres: Record<string, string>;
|
||||||
|
header_image: Record<string, string>;
|
||||||
|
icon: string;
|
||||||
|
languages: Record<string, string>;
|
||||||
|
library_assets: LibraryAssets;
|
||||||
|
library_assets_full: LibraryAssetsFull;
|
||||||
|
metacritic_fullurl: string;
|
||||||
|
metacritic_name: string;
|
||||||
|
metacritic_score: string;
|
||||||
|
name: string;
|
||||||
|
name_localized: Partial<Record<LanguageCode, string>>;
|
||||||
|
osarch: string;
|
||||||
|
osextended: string;
|
||||||
|
oslist: string;
|
||||||
|
primary_genre: string;
|
||||||
|
releasestate: string;
|
||||||
|
review_percentage: string;
|
||||||
|
review_score: string;
|
||||||
|
small_capsule: Record<string, string>;
|
||||||
|
steam_deck_compatibility: SteamDeckCompatibility;
|
||||||
|
steam_release_date: string;
|
||||||
|
store_asset_mtime: string;
|
||||||
|
store_tags: Record<string, string>;
|
||||||
|
supported_languages: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
full_audio?: string;
|
||||||
|
subtitles?: string;
|
||||||
|
supported?: string;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LibraryAssets {
|
||||||
|
library_capsule: string;
|
||||||
|
library_header: string;
|
||||||
|
library_hero: string;
|
||||||
|
library_logo: string;
|
||||||
|
logo_position: LogoPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LogoPosition {
|
||||||
|
height_pct: string;
|
||||||
|
pinned_position: string;
|
||||||
|
width_pct: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LibraryAssetsFull {
|
||||||
|
library_capsule: ImageSet;
|
||||||
|
library_header: ImageSet;
|
||||||
|
library_hero: ImageSet;
|
||||||
|
library_logo: ImageSet & { logo_position: LogoPosition };
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageSet {
|
||||||
|
image: Record<string, string>;
|
||||||
|
image2x?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamDeckCompatibility {
|
||||||
|
category: string;
|
||||||
|
configuration: Record<string, string>;
|
||||||
|
test_timestamp: string;
|
||||||
|
tested_build_id: string;
|
||||||
|
tests: Record<string, { display: string; token: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppConfig {
|
||||||
|
installdir: string;
|
||||||
|
launch: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
executable: string;
|
||||||
|
type: string;
|
||||||
|
arguments?: string;
|
||||||
|
description?: string;
|
||||||
|
description_loc?: Record<string, string>;
|
||||||
|
config?: {
|
||||||
|
betakey: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
steamcontrollertemplateindex: string;
|
||||||
|
steamdecktouchscreen: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppDepots {
|
||||||
|
branches: AppDepotBranches;
|
||||||
|
privatebranches: Record<string, AppDepotBranches>;
|
||||||
|
[depotId: string]: DepotEntry
|
||||||
|
| AppDepotBranches
|
||||||
|
| Record<string, AppDepotBranches>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface DepotEntry {
|
||||||
|
manifests: {
|
||||||
|
public: {
|
||||||
|
download: string;
|
||||||
|
gid: string;
|
||||||
|
size: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppDepotBranches {
|
||||||
|
[branchName: string]: {
|
||||||
|
buildid: string;
|
||||||
|
timeupdated: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AppExtended {
|
||||||
|
additional_dependencies: Array<{
|
||||||
|
dest_os: string;
|
||||||
|
h264: string;
|
||||||
|
src_os: string;
|
||||||
|
}>;
|
||||||
|
developer: string;
|
||||||
|
dlcavailableonstore: string;
|
||||||
|
homepage: string;
|
||||||
|
listofdlc: string;
|
||||||
|
publisher: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UFSData {
|
||||||
|
maxnumfiles: string;
|
||||||
|
quota: string;
|
||||||
|
savefiles: Array<{
|
||||||
|
path: string;
|
||||||
|
pattern: string;
|
||||||
|
recursive: string;
|
||||||
|
root: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LanguageCode =
|
||||||
|
| "english"
|
||||||
|
| "french"
|
||||||
|
| "german"
|
||||||
|
| "italian"
|
||||||
|
| "japanese"
|
||||||
|
| "koreana"
|
||||||
|
| "polish"
|
||||||
|
| "russian"
|
||||||
|
| "schinese"
|
||||||
|
| "tchinese"
|
||||||
|
| "brazilian"
|
||||||
|
| "spanish";
|
||||||
|
|
||||||
|
export interface Screenshot {
|
||||||
|
appid: number;
|
||||||
|
id: number;
|
||||||
|
filename: string;
|
||||||
|
all_ages: string;
|
||||||
|
normalized_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Category {
|
||||||
|
strDisplayName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReviewSummary {
|
||||||
|
strReviewSummary: string;
|
||||||
|
cReviews: number;
|
||||||
|
cRecommendationsPositive: number;
|
||||||
|
cRecommendationsNegative: number;
|
||||||
|
nReviewScore: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GameDetailsResponse {
|
||||||
|
strReleaseDate: string;
|
||||||
|
strDescription: string;
|
||||||
|
rgScreenshots: Screenshot[];
|
||||||
|
rgCategories: Category[];
|
||||||
|
strGenres?: string;
|
||||||
|
strFullDescription: string;
|
||||||
|
strMicroTrailerURL: string;
|
||||||
|
ReviewSummary: ReviewSummary;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the TypeScript interfaces
|
||||||
|
export interface Tag {
|
||||||
|
tagid: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TagWithSlug {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StoreTags {
|
||||||
|
[key: string]: string; // Index signature for numeric string keys to tag ID strings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface GameTagsResponse {
|
||||||
|
tags: Tag[];
|
||||||
|
success: number;
|
||||||
|
rwgrsn: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GenreType = {
|
||||||
|
type: 'genre';
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AppInfo {
|
||||||
|
name: string;
|
||||||
|
slug: string;
|
||||||
|
images: {
|
||||||
|
logo: string;
|
||||||
|
backdrop: string;
|
||||||
|
poster: string;
|
||||||
|
banner: string;
|
||||||
|
screenshots: string[];
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
links: string[] | null;
|
||||||
|
score: number;
|
||||||
|
id: string;
|
||||||
|
releaseDate: Date;
|
||||||
|
description: string | null;
|
||||||
|
compatibility: "low" | "mid" | "high" | "unknown";
|
||||||
|
controllerSupport: "partial" | "full" | "unknown";
|
||||||
|
primaryGenre: string | null;
|
||||||
|
size: { downloadSize: number; sizeOnDisk: number };
|
||||||
|
tags: Array<{ name: string; slug: string; type: "tag" }>;
|
||||||
|
genres: Array<{ type: "genre"; name: string; slug: string }>;
|
||||||
|
categories: Array<{ name: string; slug: string; type: "categorie" }>;
|
||||||
|
franchises: Array<{ name: string; slug: string; type: "franchise" }>;
|
||||||
|
developers: Array<{ name: string; slug: string; type: "developer" }>;
|
||||||
|
publishers: Array<{ name: string; slug: string; type: "publisher" }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ImageType =
|
||||||
|
| 'screenshot'
|
||||||
|
| 'boxArt'
|
||||||
|
| 'banner'
|
||||||
|
| 'backdrop'
|
||||||
|
| 'icon'
|
||||||
|
| 'logo'
|
||||||
|
| 'poster'
|
||||||
|
| 'heroArt';
|
||||||
|
|
||||||
|
export interface ImageInfo {
|
||||||
|
type: ImageType;
|
||||||
|
position: number;
|
||||||
|
hash: string;
|
||||||
|
sourceUrl: string | null;
|
||||||
|
format?: string;
|
||||||
|
averageColor: { hex: string; isDark: boolean };
|
||||||
|
dimensions: { width: number; height: number };
|
||||||
|
fileSize: number;
|
||||||
|
buffer: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompareOpts {
|
||||||
|
/** Pixelmatch color threshold (0–1). Default: 0.1 */
|
||||||
|
threshold?: number;
|
||||||
|
/** If true, return an image buffer of the diff map. Default: false */
|
||||||
|
diffOutput?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompareResult {
|
||||||
|
diffRatio: number;
|
||||||
|
/** Present only if `diffOutput: true` */
|
||||||
|
diffBuffer?: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Shot {
|
||||||
|
url: string;
|
||||||
|
buffer: Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RankedShot {
|
||||||
|
url: string;
|
||||||
|
score: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamPlayerSummaryResponse {
|
||||||
|
response: {
|
||||||
|
players: SteamPlayerSummary[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamPlayerSummary {
|
||||||
|
steamid: string;
|
||||||
|
communityvisibilitystate: number;
|
||||||
|
profilestate?: number;
|
||||||
|
personaname: string;
|
||||||
|
profileurl: string;
|
||||||
|
avatar: string;
|
||||||
|
avatarmedium: string;
|
||||||
|
avatarfull: string;
|
||||||
|
avatarhash: string;
|
||||||
|
lastlogoff?: number;
|
||||||
|
personastate: number;
|
||||||
|
realname?: string;
|
||||||
|
primaryclanid?: string;
|
||||||
|
timecreated: number;
|
||||||
|
personastateflags?: number;
|
||||||
|
loccountrycode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamPlayerBansResponse {
|
||||||
|
players: SteamPlayerBan[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamPlayerBan {
|
||||||
|
SteamId: string;
|
||||||
|
CommunityBanned: boolean;
|
||||||
|
VACBanned: boolean;
|
||||||
|
NumberOfVACBans: number;
|
||||||
|
DaysSinceLastBan: number;
|
||||||
|
NumberOfGameBans: number;
|
||||||
|
EconomyBan: 'none' | 'probation' | 'banned'; // Enum based on known possible values
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SteamAccount = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
realName: string | null;
|
||||||
|
steamMemberSince: Date;
|
||||||
|
avatarHash: string;
|
||||||
|
limitations: {
|
||||||
|
isLimited: boolean;
|
||||||
|
tradeBanState: 'none' | 'probation' | 'banned';
|
||||||
|
isVacBanned: boolean;
|
||||||
|
visibilityState: number;
|
||||||
|
privacyState: 'public' | 'private' | 'friendsonly';
|
||||||
|
};
|
||||||
|
profileUrl: string;
|
||||||
|
lastSyncedAt: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface SteamFriendsListResponse {
|
||||||
|
friendslist: {
|
||||||
|
friends: SteamFriend[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamFriend {
|
||||||
|
steamid: string;
|
||||||
|
relationship: 'friend'; // could expand this if Steam ever adds more types
|
||||||
|
friend_since: number; // Unix timestamp (seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamOwnedGamesResponse {
|
||||||
|
response: {
|
||||||
|
game_count: number;
|
||||||
|
games: SteamOwnedGame[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamOwnedGame {
|
||||||
|
appid: number;
|
||||||
|
name: string;
|
||||||
|
playtime_forever: number;
|
||||||
|
img_icon_url: string;
|
||||||
|
|
||||||
|
playtime_windows_forever?: number;
|
||||||
|
playtime_mac_forever?: number;
|
||||||
|
playtime_linux_forever?: number;
|
||||||
|
playtime_deck_forever?: number;
|
||||||
|
|
||||||
|
rtime_last_played?: number; // Unix timestamp
|
||||||
|
content_descriptorids?: number[];
|
||||||
|
playtime_disconnected?: number;
|
||||||
|
has_community_visible_stats?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The shape of the parsed Steam profile information.
|
||||||
|
*/
|
||||||
|
export interface ProfileInfo {
|
||||||
|
steamID64: string;
|
||||||
|
isLimited: boolean;
|
||||||
|
privacyState: 'public' | 'private' | 'friendsonly' | string;
|
||||||
|
visibility: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamStoreResponse {
|
||||||
|
response: {
|
||||||
|
store_items: SteamStoreItem[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamStoreItem {
|
||||||
|
item_type: number;
|
||||||
|
id: number;
|
||||||
|
success: number;
|
||||||
|
visible: boolean;
|
||||||
|
name: string;
|
||||||
|
store_url_path: string;
|
||||||
|
appid: number;
|
||||||
|
type: number;
|
||||||
|
tagids: number[];
|
||||||
|
categories: {
|
||||||
|
supported_player_categoryids?: number[];
|
||||||
|
feature_categoryids?: number[];
|
||||||
|
controller_categoryids?: number[];
|
||||||
|
};
|
||||||
|
reviews: {
|
||||||
|
summary_filtered: {
|
||||||
|
review_count: number;
|
||||||
|
percent_positive: number;
|
||||||
|
review_score: number;
|
||||||
|
review_score_label: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
basic_info: {
|
||||||
|
short_description?: string;
|
||||||
|
publishers: SteamCreator[];
|
||||||
|
developers: SteamCreator[];
|
||||||
|
franchises?: SteamCreator[];
|
||||||
|
};
|
||||||
|
tags: {
|
||||||
|
tagid: number;
|
||||||
|
weight: number;
|
||||||
|
}[];
|
||||||
|
assets: SteamAssets;
|
||||||
|
assets_without_overrides: SteamAssets;
|
||||||
|
release: {
|
||||||
|
steam_release_date: number;
|
||||||
|
};
|
||||||
|
platforms: {
|
||||||
|
windows: boolean;
|
||||||
|
mac: boolean;
|
||||||
|
steamos_linux: boolean;
|
||||||
|
vr_support: Record<string, never>;
|
||||||
|
steam_deck_compat_category?: number;
|
||||||
|
steam_os_compat_category?: number;
|
||||||
|
};
|
||||||
|
best_purchase_option: PurchaseOption;
|
||||||
|
purchase_options: PurchaseOption[];
|
||||||
|
screenshots: {
|
||||||
|
all_ages_screenshots: {
|
||||||
|
filename: string;
|
||||||
|
ordinal: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
trailers: {
|
||||||
|
highlights: Trailer[];
|
||||||
|
};
|
||||||
|
supported_languages: SupportedLanguage[];
|
||||||
|
full_description: string;
|
||||||
|
links?: {
|
||||||
|
link_type: number;
|
||||||
|
url: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamCreator {
|
||||||
|
name: string;
|
||||||
|
creator_clan_account_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamAssets {
|
||||||
|
asset_url_format: string;
|
||||||
|
main_capsule: string;
|
||||||
|
small_capsule: string;
|
||||||
|
header: string;
|
||||||
|
page_background: string;
|
||||||
|
hero_capsule: string;
|
||||||
|
hero_capsule_2x: string;
|
||||||
|
library_capsule: string;
|
||||||
|
library_capsule_2x: string;
|
||||||
|
library_hero: string;
|
||||||
|
library_hero_2x: string;
|
||||||
|
community_icon: string;
|
||||||
|
page_background_path: string;
|
||||||
|
raw_page_background: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PurchaseOption {
|
||||||
|
packageid?: number;
|
||||||
|
bundleid?: number;
|
||||||
|
purchase_option_name: string;
|
||||||
|
final_price_in_cents: string;
|
||||||
|
original_price_in_cents: string;
|
||||||
|
formatted_final_price: string;
|
||||||
|
formatted_original_price: string;
|
||||||
|
discount_pct: number;
|
||||||
|
active_discounts: ActiveDiscount[];
|
||||||
|
user_can_purchase_as_gift: boolean;
|
||||||
|
hide_discount_pct_for_compliance: boolean;
|
||||||
|
included_game_count: number;
|
||||||
|
bundle_discount_pct?: number;
|
||||||
|
price_before_bundle_discount?: string;
|
||||||
|
formatted_price_before_bundle_discount?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActiveDiscount {
|
||||||
|
discount_amount: string;
|
||||||
|
discount_description: string;
|
||||||
|
discount_end_date: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Trailer {
|
||||||
|
trailer_name: string;
|
||||||
|
trailer_url_format: string;
|
||||||
|
trailer_category: number;
|
||||||
|
trailer_480p: TrailerFile[];
|
||||||
|
trailer_max: TrailerFile[];
|
||||||
|
microtrailer: TrailerFile[];
|
||||||
|
screenshot_medium: string;
|
||||||
|
screenshot_full: string;
|
||||||
|
trailer_base_id: number;
|
||||||
|
all_ages: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TrailerFile {
|
||||||
|
filename: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SupportedLanguage {
|
||||||
|
elanguage: number;
|
||||||
|
eadditionallanguage: number;
|
||||||
|
supported: boolean;
|
||||||
|
full_audio: boolean;
|
||||||
|
subtitles: boolean;
|
||||||
|
}
|
||||||
524
packages/core/src/client/utils.ts
Normal file
524
packages/core/src/client/utils.ts
Normal file
@@ -0,0 +1,524 @@
|
|||||||
|
import type {
|
||||||
|
Tag,
|
||||||
|
StoreTags,
|
||||||
|
AppDepots,
|
||||||
|
GenreType,
|
||||||
|
LibraryAssetsFull,
|
||||||
|
DepotEntry,
|
||||||
|
CompareOpts,
|
||||||
|
CompareResult,
|
||||||
|
RankedShot,
|
||||||
|
Shot,
|
||||||
|
ProfileInfo,
|
||||||
|
} from "./types";
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import pLimit from 'p-limit';
|
||||||
|
import { PNG } from 'pngjs';
|
||||||
|
import pixelmatch from 'pixelmatch';
|
||||||
|
import { LRUCache } from 'lru-cache';
|
||||||
|
import sanitizeHtml from 'sanitize-html';
|
||||||
|
import { Agent as HttpAgent } from 'http';
|
||||||
|
import { Agent as HttpsAgent } from 'https';
|
||||||
|
import { parseStringPromise } from "xml2js";
|
||||||
|
import sharp, { type Metadata } from 'sharp';
|
||||||
|
import AbortController from 'abort-controller';
|
||||||
|
import fetch, { RequestInit } from 'node-fetch';
|
||||||
|
import { FastAverageColor } from 'fast-average-color';
|
||||||
|
|
||||||
|
const fac = new FastAverageColor()
|
||||||
|
// --- Configuration ---
|
||||||
|
const httpAgent = new HttpAgent({ keepAlive: true, maxSockets: 50 });
|
||||||
|
const httpsAgent = new HttpsAgent({ keepAlive: true, maxSockets: 50 });
|
||||||
|
const downloadCache = new LRUCache<string, Buffer>({
|
||||||
|
max: 100,
|
||||||
|
ttl: 1000 * 60 * 30, // 30-minute expiry
|
||||||
|
allowStale: false,
|
||||||
|
});
|
||||||
|
const downloadLimit = pLimit(10); // max concurrent downloads
|
||||||
|
const compareCache = new LRUCache<string, CompareResult>({
|
||||||
|
max: 50,
|
||||||
|
ttl: 1000 * 60 * 10, // 10-minute expiry
|
||||||
|
});
|
||||||
|
|
||||||
|
export namespace Utils {
|
||||||
|
export async function fetchBuffer(url: string, retries = 3): Promise<Buffer> {
|
||||||
|
if (downloadCache.has(url)) {
|
||||||
|
return downloadCache.get(url)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastError: Error | null = null;
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < retries; attempt++) {
|
||||||
|
try {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const id = setTimeout(() => controller.abort(), 15_000);
|
||||||
|
const res = await fetch(url, {
|
||||||
|
signal: controller.signal,
|
||||||
|
agent: (_parsed) => _parsed.protocol === 'http:' ? httpAgent : httpsAgent
|
||||||
|
} as RequestInit);
|
||||||
|
clearTimeout(id);
|
||||||
|
if (!res.ok) throw new Error(`Failed to fetch ${url}: ${res.status}`);
|
||||||
|
const buf = Buffer.from(await res.arrayBuffer());
|
||||||
|
downloadCache.set(url, buf);
|
||||||
|
return buf;
|
||||||
|
} catch (error: any) {
|
||||||
|
lastError = error as Error;
|
||||||
|
console.warn(`Attempt ${attempt + 1} failed for ${url}: ${error.message}`);
|
||||||
|
if (attempt < retries - 1) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw lastError || new Error(`Failed to fetch ${url} after ${retries} attempts`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getImageMetadata(buffer: Buffer) {
|
||||||
|
const hash = crypto.createHash('sha256').update(buffer).digest('hex');
|
||||||
|
const { width, height, format, size: fileSize } = await sharp(buffer).metadata();
|
||||||
|
if (!width || !height) throw new Error('Invalid dimensions');
|
||||||
|
|
||||||
|
const slice = await sharp(buffer)
|
||||||
|
.resize({ width: Math.min(width, 256) }) // cheap shrink
|
||||||
|
.ensureAlpha()
|
||||||
|
.raw()
|
||||||
|
.toBuffer();
|
||||||
|
|
||||||
|
const pixelArray = new Uint8Array(slice.buffer);
|
||||||
|
const { hex, isDark } = fac.prepareResult(fac.getColorFromArray4(pixelArray, { mode: "precision" }));
|
||||||
|
|
||||||
|
return { hash, format, averageColor: { hex, isDark }, dimensions: { width, height }, fileSize, buffer };
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Optimized Box Art creation ---
|
||||||
|
export async function createBoxArtBuffer(
|
||||||
|
logoUrl: string,
|
||||||
|
backgroundUrl: string,
|
||||||
|
logoPercent = 0.9
|
||||||
|
): Promise<Buffer> {
|
||||||
|
const [bgBuf, logoBuf] = await Promise.all([
|
||||||
|
downloadLimit(() =>
|
||||||
|
fetchBuffer(backgroundUrl)
|
||||||
|
.catch(error => {
|
||||||
|
console.error(`Failed to download hero image from ${backgroundUrl}:`, error);
|
||||||
|
throw new Error(`Failed to create box art: hero image unavailable`);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
downloadLimit(() => fetchBuffer(logoUrl)
|
||||||
|
.catch(error => {
|
||||||
|
console.error(`Failed to download logo image from ${logoUrl}:`, error);
|
||||||
|
throw new Error(`Failed to create box art: logo image unavailable`);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const bgImage = sharp(bgBuf);
|
||||||
|
const meta = await bgImage.metadata();
|
||||||
|
if (!meta.width || !meta.height) throw new Error('Invalid background dimensions');
|
||||||
|
const size = Math.min(meta.width, meta.height);
|
||||||
|
const left = Math.floor((meta.width - size) / 2);
|
||||||
|
const top = Math.floor((meta.height - size) / 2);
|
||||||
|
const squareBg = bgImage.extract({ left, top, width: size, height: size });
|
||||||
|
|
||||||
|
// Resize logo
|
||||||
|
const logoTarget = Math.floor(size * logoPercent);
|
||||||
|
const logoResized = await sharp(logoBuf).resize({ width: logoTarget }).toBuffer();
|
||||||
|
const logoMeta = await sharp(logoResized).metadata();
|
||||||
|
if (!logoMeta.width || !logoMeta.height) throw new Error('Invalid logo dimensions');
|
||||||
|
const logoLeft = Math.floor((size - logoMeta.width) / 2);
|
||||||
|
const logoTop = Math.floor((size - logoMeta.height) / 2);
|
||||||
|
|
||||||
|
return await squareBg
|
||||||
|
.composite([{ input: logoResized, left: logoLeft, top: logoTop }])
|
||||||
|
.jpeg({ quality: 100 })
|
||||||
|
.toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch JSON from the given URL, with Steam-like headers
|
||||||
|
*/
|
||||||
|
export async function fetchApi<T>(url: string, retries = 3): Promise<T> {
|
||||||
|
let lastError: Error | null = null;
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < retries; attempt++) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
agent: (_parsed) => _parsed.protocol === 'http:' ? httpAgent : httpsAgent,
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"User-Agent": "Steam 1291812 / iPhone",
|
||||||
|
"Accept-Language": "en-us",
|
||||||
|
},
|
||||||
|
} as RequestInit);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`API error: ${response.status} ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await response.json()) as T;
|
||||||
|
} catch (error: any) {
|
||||||
|
lastError = error as Error;
|
||||||
|
// Only retry on network errors or 5xx status codes
|
||||||
|
if (error.message.includes('API error: 5') || !error.message.includes('API error')) {
|
||||||
|
console.warn(`Attempt ${attempt + 1} failed for ${url}: ${error.message}`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, attempt)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw lastError || new Error(`Failed to fetch ${url} after ${retries} attempts`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a slug from a name
|
||||||
|
*/
|
||||||
|
export function createSlug(name: string): string {
|
||||||
|
return name
|
||||||
|
.toLowerCase()
|
||||||
|
.normalize("NFKD") // Normalize to decompose accented characters
|
||||||
|
.replace(/[^\p{L}\p{N}\s-]/gu, '') // Keep Unicode letters, numbers, spaces, and hyphens
|
||||||
|
.replace(/\s+/g, '-') // Replace spaces with hyphens
|
||||||
|
.replace(/-+/g, '-') // Collapse multiple hyphens
|
||||||
|
.replace(/^-+|-+$/g, '') // Trim leading/trailing hyphens
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare a candidate screenshot against a UI-free baseline to find how much UI/HUD remains.
|
||||||
|
*
|
||||||
|
* @param baselineBuffer - PNG/JPEG buffer of the clean background.
|
||||||
|
* @param candidateBuffer - PNG/JPEG buffer of the screenshot to test.
|
||||||
|
* @param opts - Options.
|
||||||
|
* @returns Promise resolving to diff ratio (and optional diff image).
|
||||||
|
*/
|
||||||
|
export async function compareWithBaseline(
|
||||||
|
baselineBuffer: Buffer,
|
||||||
|
candidateBuffer: Buffer,
|
||||||
|
opts: CompareOpts = {}
|
||||||
|
): Promise<CompareResult> {
|
||||||
|
// Generate cache key from buffer hashes
|
||||||
|
const baseHash = crypto.createHash('md5').update(baselineBuffer).digest('hex');
|
||||||
|
const candHash = crypto.createHash('md5').update(candidateBuffer).digest('hex');
|
||||||
|
const optsKey = JSON.stringify(opts);
|
||||||
|
const cacheKey = `${baseHash}:${candHash}:${optsKey}`;
|
||||||
|
|
||||||
|
// Check cache
|
||||||
|
if (compareCache.has(cacheKey)) {
|
||||||
|
return compareCache.get(cacheKey)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { threshold = 0.1, diffOutput = false } = opts;
|
||||||
|
|
||||||
|
// Get dimensions of baseline
|
||||||
|
const baseMeta: Metadata = await sharp(baselineBuffer).metadata();
|
||||||
|
if (!baseMeta.width || !baseMeta.height) {
|
||||||
|
throw new Error('Invalid baseline dimensions');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produce PNG buffers of same size
|
||||||
|
const [pngBaseBuf, pngCandBuf] = await Promise.all([
|
||||||
|
sharp(baselineBuffer).png().toBuffer(),
|
||||||
|
sharp(candidateBuffer)
|
||||||
|
.resize(baseMeta.width, baseMeta.height)
|
||||||
|
.png()
|
||||||
|
.toBuffer(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const imgBase = PNG.sync.read(pngBaseBuf);
|
||||||
|
const imgCand = PNG.sync.read(pngCandBuf);
|
||||||
|
const diffImg = new PNG({ width: baseMeta.width, height: baseMeta.height });
|
||||||
|
|
||||||
|
const numDiff = pixelmatch(
|
||||||
|
imgBase.data,
|
||||||
|
imgCand.data,
|
||||||
|
diffImg.data,
|
||||||
|
baseMeta.width,
|
||||||
|
baseMeta.height,
|
||||||
|
{ threshold }
|
||||||
|
);
|
||||||
|
|
||||||
|
const total = baseMeta.width * baseMeta.height;
|
||||||
|
const diffRatio = numDiff / total;
|
||||||
|
|
||||||
|
const result: CompareResult = { diffRatio };
|
||||||
|
if (diffOutput) {
|
||||||
|
result.diffBuffer = PNG.sync.write(diffImg);
|
||||||
|
}
|
||||||
|
|
||||||
|
compareCache.set(cacheKey, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a baseline buffer and an array of screenshots, returns them sorted
|
||||||
|
* ascending by diffRatio (least UI first).
|
||||||
|
*/
|
||||||
|
export async function rankScreenshots(
|
||||||
|
baselineBuffer: Buffer,
|
||||||
|
shots: Shot[],
|
||||||
|
opts: CompareOpts = {}
|
||||||
|
): Promise<RankedShot[]> {
|
||||||
|
// Process up to 5 comparisons in parallel
|
||||||
|
const compareLimit = pLimit(5);
|
||||||
|
|
||||||
|
// Run all comparisons with limited concurrency
|
||||||
|
const results = await Promise.all(
|
||||||
|
shots.map(shot =>
|
||||||
|
compareLimit(async () => {
|
||||||
|
const { diffRatio } = await compareWithBaseline(
|
||||||
|
baselineBuffer,
|
||||||
|
shot.buffer,
|
||||||
|
opts
|
||||||
|
);
|
||||||
|
return { url: shot.url, score: diffRatio };
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return results.sort((a, b) => a.score - b.score);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Helpers for URLs ---
|
||||||
|
export function getScreenshotUrls(screenshots: { appid: number; filename: string }[]): string[] {
|
||||||
|
return screenshots.map(s => `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${s.appid}/${s.filename}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAssetUrls(assets: LibraryAssetsFull, appid: number | string, header: string) {
|
||||||
|
const base = `https://shared.cloudflare.steamstatic.com/store_item_assets/steam/apps/${appid}`;
|
||||||
|
return {
|
||||||
|
logo: `${base}/${assets.library_logo?.image2x?.english || assets.library_logo?.image?.english}`,
|
||||||
|
backdrop: `${base}/${assets.library_hero?.image2x?.english || assets.library_hero?.image?.english}`,
|
||||||
|
poster: `${base}/${assets.library_capsule?.image2x?.english || assets.library_capsule?.image?.english}`,
|
||||||
|
banner: `${base}/${assets.library_header?.image2x?.english || assets.library_header?.image?.english || header}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute a 0–5 score from positive/negative votes using a Wilson score confidence interval.
|
||||||
|
* This formula adjusts the raw ratio based on the total number of votes to account for
|
||||||
|
* statistical confidence. With few votes, the score regresses toward 2.5 (neutral).
|
||||||
|
*
|
||||||
|
* Compute a 0–5 score from positive/negative votes
|
||||||
|
*/
|
||||||
|
export function getRating(positive: number, negative: number): number {
|
||||||
|
const total = positive + negative;
|
||||||
|
if (!total) return 0;
|
||||||
|
const avg = positive / total;
|
||||||
|
// Apply Wilson score confidence adjustment and scale to 0-5 range
|
||||||
|
const score = avg - (avg - 0.5) * Math.pow(2, -Math.log10(total + 1));
|
||||||
|
return Math.round(score * 5 * 10) / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAssociationsByTypeWithSlug<
|
||||||
|
T extends "developer" | "publisher"
|
||||||
|
>(
|
||||||
|
associations: Record<string, { name: string; type: string }>,
|
||||||
|
type: T
|
||||||
|
): Array<{ name: string; slug: string; type: T }> {
|
||||||
|
return Object.values(associations)
|
||||||
|
.filter((a) => a.type === type)
|
||||||
|
.map((a) => ({ name: a.name.trim(), slug: createSlug(a.name.trim()), type }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compatibilityType(type?: string): "low" | "mid" | "high" | "unknown" {
|
||||||
|
switch (type) {
|
||||||
|
case "1":
|
||||||
|
return "high";
|
||||||
|
case "2":
|
||||||
|
return "mid";
|
||||||
|
case "3":
|
||||||
|
return "low";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function estimateRatingFromSummary(
|
||||||
|
reviewCount: number,
|
||||||
|
percentPositive: number
|
||||||
|
): number {
|
||||||
|
const positiveVotes = Math.round((percentPositive / 100) * reviewCount);
|
||||||
|
const negativeVotes = reviewCount - positiveVotes;
|
||||||
|
return getRating(positiveVotes, negativeVotes);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapGameTags<
|
||||||
|
T extends string = "tag"
|
||||||
|
>(
|
||||||
|
available: Tag[],
|
||||||
|
storeTags: StoreTags,
|
||||||
|
): Array<{ name: string; slug: string; type: T }> {
|
||||||
|
const tagMap = new Map<number, Tag>(available.map((t) => [t.tagid, t]));
|
||||||
|
const result: Array<{ name: string; slug: string; type: T }> = Object.values(storeTags)
|
||||||
|
.map((id) => tagMap.get(Number(id)))
|
||||||
|
.filter((t): t is Tag => Boolean(t))
|
||||||
|
.map((t) => ({ name: t.name.trim(), slug: createSlug(t.name), type: 'tag' as T }));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createType<
|
||||||
|
T extends "developer" | "publisher" | "franchise" | "tag" | "categorie" | "genre"
|
||||||
|
>(
|
||||||
|
names: string[],
|
||||||
|
type: T
|
||||||
|
) {
|
||||||
|
return names
|
||||||
|
.map(name => ({
|
||||||
|
type,
|
||||||
|
name: name.trim(),
|
||||||
|
slug: createSlug(name.trim())
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a tag object with name, slug, and type
|
||||||
|
* @typeparam T Literal type of the `type` field (defaults to 'tag')
|
||||||
|
*/
|
||||||
|
export function createTag<
|
||||||
|
T extends string = 'tag'
|
||||||
|
>(
|
||||||
|
name: string,
|
||||||
|
type?: T
|
||||||
|
): { name: string; slug: string; type: T } {
|
||||||
|
const tagType = (type ?? 'tag') as T;
|
||||||
|
return {
|
||||||
|
name: name.trim(),
|
||||||
|
slug: createSlug(name),
|
||||||
|
type: tagType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function capitalise(name: string) {
|
||||||
|
return name
|
||||||
|
.charAt(0) // first character
|
||||||
|
.toUpperCase() // make it uppercase
|
||||||
|
+ name
|
||||||
|
.slice(1) // rest of the string
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDepotEntry(e: any): e is DepotEntry {
|
||||||
|
return (
|
||||||
|
e != null &&
|
||||||
|
typeof e === 'object' &&
|
||||||
|
'manifests' in e &&
|
||||||
|
e.manifests != null &&
|
||||||
|
typeof e.manifests.public?.download === 'string'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPublicDepotSizes(depots: AppDepots) {
|
||||||
|
let download = 0;
|
||||||
|
let size = 0;
|
||||||
|
|
||||||
|
for (const key of Object.keys(depots)) {
|
||||||
|
if (key === 'branches' || key === 'privatebranches') continue;
|
||||||
|
const entry = depots[key] as DepotEntry;
|
||||||
|
if (!isDepotEntry(entry)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dl = Number(entry.manifests.public.download);
|
||||||
|
const sz = Number(entry.manifests.public.size);
|
||||||
|
if (!Number.isFinite(dl) || !Number.isFinite(sz)) {
|
||||||
|
console.warn(`[getPublicDepotSizes] non-numeric size for depot ${key}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
download += dl;
|
||||||
|
size += sz;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { downloadSize: download, sizeOnDisk: size };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseGenres(str: string): GenreType[] {
|
||||||
|
return str.split(',')
|
||||||
|
.map((g) => g.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((g) => ({ type: 'genre', name: g.trim(), slug: createSlug(g) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPrimaryGenre(
|
||||||
|
genres: GenreType[],
|
||||||
|
map: Record<string, string>,
|
||||||
|
primaryId: string
|
||||||
|
): string | null {
|
||||||
|
const idx = Object.keys(map).find((k) => map[k] === primaryId);
|
||||||
|
return idx !== undefined ? genres[Number(idx)]?.name : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanDescription(input: string): string {
|
||||||
|
|
||||||
|
const cleaned = sanitizeHtml(input, {
|
||||||
|
allowedTags: [], // no tags allowed
|
||||||
|
allowedAttributes: {}, // no attributes anywhere
|
||||||
|
textFilter: (text) => text.replace(/\s+/g, ' '), // collapse runs of whitespace
|
||||||
|
});
|
||||||
|
|
||||||
|
return cleaned.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches and parses a single Steam community profile XML.
|
||||||
|
* @param steamIdOrVanity - The 64-bit SteamID or vanity name.
|
||||||
|
* @returns Promise resolving to ProfileInfo.
|
||||||
|
*/
|
||||||
|
export async function fetchProfileInfo(
|
||||||
|
steamIdOrVanity: string
|
||||||
|
): Promise<ProfileInfo> {
|
||||||
|
const isNumericId = /^\d+$/.test(steamIdOrVanity);
|
||||||
|
const path = isNumericId ? `profiles/${steamIdOrVanity}` : `id/${steamIdOrVanity}`;
|
||||||
|
const url = `https://steamcommunity.com/${path}/?xml=1`;
|
||||||
|
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch ${steamIdOrVanity}: HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const xml = await response.text();
|
||||||
|
const { profile } = await parseStringPromise(xml, {
|
||||||
|
explicitArray: false,
|
||||||
|
trim: true,
|
||||||
|
mergeAttrs: true
|
||||||
|
}) as { profile: any };
|
||||||
|
|
||||||
|
// Extract fields (fall back to limitedAccount tag if needed)
|
||||||
|
const limitedFlag = profile.isLimitedAccount ?? profile.limitedAccount;
|
||||||
|
const isLimited = limitedFlag === '1';
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLimited,
|
||||||
|
steamID64: profile.steamID64,
|
||||||
|
privacyState: profile.privacyState,
|
||||||
|
visibility: profile.visibilityState
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Batch-fetches multiple Steam profiles in parallel.
|
||||||
|
* @param idsOrVanities - Array of SteamID64 strings or vanity names.
|
||||||
|
* @returns Promise resolving to a record mapping each input to its ProfileInfo or an error.
|
||||||
|
*/
|
||||||
|
export async function fetchProfilesInfo(
|
||||||
|
idsOrVanities: string[]
|
||||||
|
): Promise<Map<string, ProfileInfo | { error: string }>> {
|
||||||
|
const results = await Promise.all(
|
||||||
|
idsOrVanities.map(async (input) => {
|
||||||
|
try {
|
||||||
|
const info = await fetchProfileInfo(input);
|
||||||
|
return { input, result: info };
|
||||||
|
} catch (err) {
|
||||||
|
return { input, result: { error: (err as Error).message } };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return new Map(
|
||||||
|
results.map(({ input, result }) => [input, result] as [string, ProfileInfo | { error: string }])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
import { z } from "zod";
|
|
||||||
import "zod-openapi/extend";
|
import "zod-openapi/extend";
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
|
|
||||||
export module Common {
|
export namespace Common {
|
||||||
export const IdDescription = `Unique object identifier.
|
export const IdDescription = `Unique object identifier.
|
||||||
The format and length of IDs may change over time.`;
|
The format and length of IDs may change over time.`;
|
||||||
|
|
||||||
|
export const now = () => sql`now()`;
|
||||||
|
export const utc = () => sql`now() at time zone 'utc'`;
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user