mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +02:00
⭐ feat(api): Connect Steam to main user account (#262)
## Description This attempts to connect the Steam account to user account... for easier management <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Enhanced user profiles and account views now display integrated Steam account details and enriched team associations for a more comprehensive experience. - **Chores** - Backend and database refinements have been implemented to improve system stability, data integrity, and overall performance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -4,8 +4,6 @@ import { domain } from "./dns";
|
|||||||
import { secret } from "./secret";
|
import { secret } from "./secret";
|
||||||
import { postgres } from "./postgres";
|
import { postgres } from "./postgres";
|
||||||
import { cluster } from "./cluster";
|
import { cluster } from "./cluster";
|
||||||
import { vpc } from "./vpc";
|
|
||||||
|
|
||||||
// sst.Linkable.wrap(random.RandomString, (resource) => ({
|
// sst.Linkable.wrap(random.RandomString, (resource) => ({
|
||||||
// properties: {
|
// properties: {
|
||||||
// value: resource.result,
|
// value: resource.result,
|
||||||
|
|||||||
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";
|
||||||
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": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,20 @@
|
|||||||
"when": 1744287542918,
|
"when": 1744287542918,
|
||||||
"tag": "0003_first_big_bertha",
|
"tag": "0003_first_big_bertha",
|
||||||
"breakpoints": true
|
"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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"loops": "^3.4.1",
|
"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",
|
"uuid": "^11.0.3",
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.1",
|
||||||
|
|||||||
@@ -3,34 +3,6 @@ export namespace Examples {
|
|||||||
export const Id = (prefix: keyof typeof prefixes) =>
|
export const Id = (prefix: keyof typeof prefixes) =>
|
||||||
`${prefixes[prefix]}_XXXXXXXXXXXXXXXXXXXXXXXXX`;
|
`${prefixes[prefix]}_XXXXXXXXXXXXXXXXXXXXXXXXX`;
|
||||||
|
|
||||||
export const User = {
|
|
||||||
id: Id("user"),
|
|
||||||
name: "John Doe",
|
|
||||||
email: "john@example.com",
|
|
||||||
discriminator: 47,
|
|
||||||
avatarUrl: "https://cdn.discordapp.com/avatars/xxxxxxx/xxxxxxx.png",
|
|
||||||
polarCustomerID: "0bfcb712-df13-4454-81a8-fbee66eddca4",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Team = {
|
|
||||||
id: Id("team"),
|
|
||||||
name: "John Does' Team",
|
|
||||||
slug: "john_doe",
|
|
||||||
planType: "BYOG" as const
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Member = {
|
|
||||||
id: Id("member"),
|
|
||||||
email: "john@example.com",
|
|
||||||
teamID: Id("team"),
|
|
||||||
timeSeen: new Date("2025-02-23T13:39:52.249Z"),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Polar = {
|
|
||||||
teamID: Id("team"),
|
|
||||||
timeSeen: new Date("2025-02-23T13:39:52.249Z"),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Steam = {
|
export const Steam = {
|
||||||
id: Id("steam"),
|
id: Id("steam"),
|
||||||
userID: Id("user"),
|
userID: Id("user"),
|
||||||
@@ -52,6 +24,35 @@ export namespace Examples {
|
|||||||
avatarUrl: "https://avatars.akamai.steamstatic.com/XXXXXXXXXXXX_full.jpg",
|
avatarUrl: "https://avatars.akamai.steamstatic.com/XXXXXXXXXXXX_full.jpg",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const User = {
|
||||||
|
id: Id("user"),
|
||||||
|
name: "John Doe",
|
||||||
|
email: "john@example.com",
|
||||||
|
discriminator: 47,
|
||||||
|
avatarUrl: "https://cdn.discordapp.com/avatars/xxxxxxx/xxxxxxx.png",
|
||||||
|
polarCustomerID: "0bfcb712-df13-4454-81a8-fbee66eddca4",
|
||||||
|
steamAccounts: [Steam]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Team = {
|
||||||
|
id: Id("team"),
|
||||||
|
name: "John Does' Team",
|
||||||
|
slug: "john_doe",
|
||||||
|
planType: "BYOG" as const
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Member = {
|
||||||
|
id: Id("member"),
|
||||||
|
email: "john@example.com",
|
||||||
|
teamID: Id("team"),
|
||||||
|
timeSeen: new Date("2025-02-23T13:39:52.249Z"),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Polar = {
|
||||||
|
teamID: Id("team"),
|
||||||
|
timeSeen: new Date("2025-02-23T13:39:52.249Z"),
|
||||||
|
}
|
||||||
|
|
||||||
export const Machine = {
|
export const Machine = {
|
||||||
id: Id("machine"),
|
id: Id("machine"),
|
||||||
userID: Id("user"),
|
userID: Id("user"),
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ export namespace Machine {
|
|||||||
description: Common.IdDescription,
|
description: Common.IdDescription,
|
||||||
example: Examples.Machine.id,
|
example: Examples.Machine.id,
|
||||||
}),
|
}),
|
||||||
userID: z.string().nullable().openapi({
|
// userID: z.string().nullable().openapi({
|
||||||
description: "The userID of the user who owns this machine, in the case of BYOG",
|
// description: "The userID of the user who owns this machine, in the case of BYOG",
|
||||||
example: Examples.Machine.userID
|
// example: Examples.Machine.userID
|
||||||
}),
|
// }),
|
||||||
country: z.string().openapi({
|
country: z.string().openapi({
|
||||||
description: "The fullname of the country this machine is running in",
|
description: "The fullname of the country this machine is running in",
|
||||||
example: Examples.Machine.country
|
example: Examples.Machine.country
|
||||||
@@ -55,7 +55,7 @@ export namespace Machine {
|
|||||||
timezone: input.timezone,
|
timezone: input.timezone,
|
||||||
fingerprint: input.fingerprint,
|
fingerprint: input.fingerprint,
|
||||||
countryCode: input.countryCode,
|
countryCode: input.countryCode,
|
||||||
userID: input.userID,
|
// userID: input.userID,
|
||||||
location: { x: input.location.longitude, y: input.location.latitude },
|
location: { x: input.location.longitude, y: input.location.latitude },
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -68,26 +68,26 @@ export namespace Machine {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
export const fromUserID = fn(z.string(), async (userID) =>
|
// export const fromUserID = fn(z.string(), async (userID) =>
|
||||||
useTransaction(async (tx) =>
|
// useTransaction(async (tx) =>
|
||||||
tx
|
// tx
|
||||||
.select()
|
// .select()
|
||||||
.from(machineTable)
|
// .from(machineTable)
|
||||||
.where(and(eq(machineTable.userID, userID), isNull(machineTable.timeDeleted)))
|
// .where(and(eq(machineTable.userID, userID), isNull(machineTable.timeDeleted)))
|
||||||
.then((rows) => rows.map(serialize))
|
// .then((rows) => rows.map(serialize))
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
|
|
||||||
export const list = fn(z.void(), async () =>
|
// export const list = fn(z.void(), async () =>
|
||||||
useTransaction(async (tx) =>
|
// useTransaction(async (tx) =>
|
||||||
tx
|
// tx
|
||||||
.select()
|
// .select()
|
||||||
.from(machineTable)
|
// .from(machineTable)
|
||||||
// Show only hosted machines, not BYOG machines
|
// // Show only hosted machines, not BYOG machines
|
||||||
.where(and(isNull(machineTable.userID), isNull(machineTable.timeDeleted)))
|
// .where(and(isNull(machineTable.userID), isNull(machineTable.timeDeleted)))
|
||||||
.then((rows) => rows.map(serialize))
|
// .then((rows) => rows.map(serialize))
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
|
|
||||||
export const fromID = fn(Info.shape.id, async (id) =>
|
export const fromID = fn(Info.shape.id, async (id) =>
|
||||||
useTransaction(async (tx) =>
|
useTransaction(async (tx) =>
|
||||||
@@ -144,7 +144,7 @@ export namespace Machine {
|
|||||||
): z.infer<typeof Info> {
|
): z.infer<typeof Info> {
|
||||||
return {
|
return {
|
||||||
id: input.id,
|
id: input.id,
|
||||||
userID: input.userID,
|
// userID: input.userID,
|
||||||
country: input.country,
|
country: input.country,
|
||||||
timezone: input.timezone,
|
timezone: input.timezone,
|
||||||
fingerprint: input.fingerprint,
|
fingerprint: input.fingerprint,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export const machineTable = pgTable(
|
|||||||
{
|
{
|
||||||
...id,
|
...id,
|
||||||
...timestamps,
|
...timestamps,
|
||||||
userID: ulid("user_id"),
|
// userID: ulid("user_id"),
|
||||||
country: text('country').notNull(),
|
country: text('country').notNull(),
|
||||||
timezone: text('timezone').notNull(),
|
timezone: text('timezone').notNull(),
|
||||||
location: point('location', { mode: 'xy' }).notNull(),
|
location: point('location', { mode: 'xy' }).notNull(),
|
||||||
@@ -35,6 +35,6 @@ export const machineTable = pgTable(
|
|||||||
(table) => [
|
(table) => [
|
||||||
// uniqueIndex("external_id").on(table.externalID),
|
// uniqueIndex("external_id").on(table.externalID),
|
||||||
uniqueIndex("machine_fingerprint").on(table.fingerprint),
|
uniqueIndex("machine_fingerprint").on(table.fingerprint),
|
||||||
primaryKey({ columns: [table.userID, table.id], }),
|
// primaryKey({ columns: [table.userID, table.id], }),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { timestamps, userID, utc } from "../drizzle/types";
|
import { id, timestamps, ulid, userID, utc } from "../drizzle/types";
|
||||||
import { index, pgTable, integer, uniqueIndex, varchar, text, primaryKey, json } from "drizzle-orm/pg-core";
|
import { index, pgTable, integer, uniqueIndex, varchar, text, primaryKey, json } from "drizzle-orm/pg-core";
|
||||||
|
import { userTable } from "../user/user.sql";
|
||||||
|
|
||||||
|
|
||||||
// public string Username { get; set; } = string.Empty;
|
// public string Username { get; set; } = string.Empty;
|
||||||
@@ -37,9 +38,14 @@ export type AccountLimitation = z.infer<typeof AccountLimitation>;
|
|||||||
export const steamTable = pgTable(
|
export const steamTable = pgTable(
|
||||||
"steam",
|
"steam",
|
||||||
{
|
{
|
||||||
...userID,
|
...id,
|
||||||
...timestamps,
|
...timestamps,
|
||||||
lastSeen: utc("time_seen"),
|
userID: ulid("user_id")
|
||||||
|
.notNull()
|
||||||
|
.references(() => userTable.id, {
|
||||||
|
onDelete: "cascade",
|
||||||
|
}),
|
||||||
|
lastSeen: utc("last_seen").notNull(),
|
||||||
steamID: integer("steam_id").notNull(),
|
steamID: integer("steam_id").notNull(),
|
||||||
avatarUrl: text("avatar_url").notNull(),
|
avatarUrl: text("avatar_url").notNull(),
|
||||||
lastGame: json("last_game").$type<LastGame>().notNull(),
|
lastGame: json("last_game").$type<LastGame>().notNull(),
|
||||||
@@ -48,11 +54,5 @@ export const steamTable = pgTable(
|
|||||||
steamEmail: varchar("steam_email", { length: 255 }).notNull(),
|
steamEmail: varchar("steam_email", { length: 255 }).notNull(),
|
||||||
personaName: varchar("persona_name", { length: 255 }).notNull(),
|
personaName: varchar("persona_name", { length: 255 }).notNull(),
|
||||||
limitation: json("limitation").$type<AccountLimitation>().notNull(),
|
limitation: json("limitation").$type<AccountLimitation>().notNull(),
|
||||||
},
|
}
|
||||||
(table) => [
|
|
||||||
primaryKey({
|
|
||||||
columns: [table.userID, table.id],
|
|
||||||
}),
|
|
||||||
uniqueIndex("steam_email").on(table.userID, table.steamEmail),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
@@ -6,13 +6,16 @@ import { Polar } from "../polar/index";
|
|||||||
import { createID, fn } from "../utils";
|
import { createID, fn } from "../utils";
|
||||||
import { userTable } from "./user.sql";
|
import { userTable } from "./user.sql";
|
||||||
import { createEvent } from "../event";
|
import { createEvent } from "../event";
|
||||||
|
import { pipe, groupBy, values, map } from "remeda";
|
||||||
import { Examples } from "../examples";
|
import { Examples } from "../examples";
|
||||||
import { Resource } from "sst/resource";
|
import { Resource } from "sst/resource";
|
||||||
import { teamTable } from "../team/team.sql";
|
import { teamTable } from "../team/team.sql";
|
||||||
|
import { steamTable } from "../steam/steam.sql";
|
||||||
import { assertActor, withActor } from "../actor";
|
import { assertActor, withActor } from "../actor";
|
||||||
import { memberTable } from "../member/member.sql";
|
import { memberTable } from "../member/member.sql";
|
||||||
import { and, eq, isNull, asc, getTableColumns, sql } from "../drizzle";
|
import { and, eq, isNull, asc, getTableColumns, sql } from "../drizzle";
|
||||||
import { afterTx, createTransaction, useTransaction } from "../drizzle/transaction";
|
import { afterTx, createTransaction, useTransaction } from "../drizzle/transaction";
|
||||||
|
import { Steam } from "../steam";
|
||||||
|
|
||||||
|
|
||||||
export namespace User {
|
export namespace User {
|
||||||
@@ -44,6 +47,10 @@ export namespace User {
|
|||||||
description: "The (number) discriminator for this user",
|
description: "The (number) discriminator for this user",
|
||||||
example: Examples.User.discriminator,
|
example: Examples.User.discriminator,
|
||||||
}),
|
}),
|
||||||
|
steamAccounts: Steam.Info.array().openapi({
|
||||||
|
description: "The steam accounts for this user",
|
||||||
|
example: Examples.User.steamAccounts,
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
.openapi({
|
.openapi({
|
||||||
ref: "User",
|
ref: "User",
|
||||||
@@ -102,7 +109,7 @@ export namespace User {
|
|||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
|
|
||||||
export const create = fn(Info.omit({ polarCustomerID: true, discriminator: true }).partial({ avatarUrl: true, id: true }), async (input) => {
|
export const create = fn(Info.omit({ polarCustomerID: true, discriminator: true, steamAccounts: true }).partial({ avatarUrl: true, id: true }), async (input) => {
|
||||||
const userID = createID("user")
|
const userID = createID("user")
|
||||||
|
|
||||||
//FIXME: Do this much later, as Polar.sh has so many inconsistencies for fuck's sake
|
//FIXME: Do this much later, as Polar.sh has so many inconsistencies for fuck's sake
|
||||||
@@ -147,41 +154,92 @@ export namespace User {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const fromEmail = fn(z.string(), async (email) =>
|
export const fromEmail = fn(z.string(), async (email) =>
|
||||||
useTransaction(async (tx) =>
|
useTransaction(async (tx) => {
|
||||||
tx
|
const rows = await tx
|
||||||
.select()
|
.select()
|
||||||
.from(userTable)
|
.from(userTable)
|
||||||
|
.leftJoin(steamTable, eq(userTable.id, steamTable.userID))
|
||||||
.where(and(eq(userTable.email, email), isNull(userTable.timeDeleted)))
|
.where(and(eq(userTable.email, email), isNull(userTable.timeDeleted)))
|
||||||
.orderBy(asc(userTable.timeCreated))
|
.orderBy(asc(userTable.timeCreated))
|
||||||
.then((rows) => rows.map(serialize))
|
|
||||||
.then((rows) => rows.at(0))
|
const result = pipe(
|
||||||
),
|
rows,
|
||||||
|
groupBy((row) => row.user.id),
|
||||||
|
values(),
|
||||||
|
map(
|
||||||
|
(group): Info => ({
|
||||||
|
id: group[0].user.id,
|
||||||
|
name: group[0].user.name,
|
||||||
|
email: group[0].user.email,
|
||||||
|
avatarUrl: group[0].user.avatarUrl,
|
||||||
|
discriminator: group[0].user.discriminator,
|
||||||
|
polarCustomerID: group[0].user.polarCustomerID,
|
||||||
|
steamAccounts: !group[0].steam ?
|
||||||
|
[] :
|
||||||
|
group.map((row) => ({
|
||||||
|
id: row.steam!.id,
|
||||||
|
userID: row.steam!.userID,
|
||||||
|
steamID: row.steam!.steamID,
|
||||||
|
lastSeen: row.steam!.lastSeen,
|
||||||
|
avatarUrl: row.steam!.avatarUrl,
|
||||||
|
lastGame: row.steam!.lastGame,
|
||||||
|
username: row.steam!.username,
|
||||||
|
countryCode: row.steam!.countryCode,
|
||||||
|
steamEmail: row.steam!.steamEmail,
|
||||||
|
personaName: row.steam!.personaName,
|
||||||
|
limitation: row.steam!.limitation,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result[0]
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const fromID = fn(z.string(), async (id) =>
|
export const fromID = fn(z.string(), async (id) =>
|
||||||
useTransaction(async (tx) =>
|
useTransaction(async (tx) => {
|
||||||
tx
|
const rows = await tx
|
||||||
.select()
|
.select()
|
||||||
.from(userTable)
|
.from(userTable)
|
||||||
|
.leftJoin(steamTable, eq(userTable.id, steamTable.userID))
|
||||||
.where(and(eq(userTable.id, id), isNull(userTable.timeDeleted)))
|
.where(and(eq(userTable.id, id), isNull(userTable.timeDeleted)))
|
||||||
.orderBy(asc(userTable.timeCreated))
|
.orderBy(asc(userTable.timeCreated))
|
||||||
.then((rows) => rows.map(serialize))
|
|
||||||
.then((rows) => rows.at(0))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
export function serialize(
|
const result = pipe(
|
||||||
input: typeof userTable.$inferSelect,
|
rows,
|
||||||
): z.infer<typeof Info> {
|
groupBy((row) => row.user.id),
|
||||||
return {
|
values(),
|
||||||
id: input.id,
|
map(
|
||||||
name: input.name,
|
(group): Info => ({
|
||||||
email: input.email,
|
id: group[0].user.id,
|
||||||
avatarUrl: input.avatarUrl,
|
name: group[0].user.name,
|
||||||
discriminator: input.discriminator,
|
email: group[0].user.email,
|
||||||
polarCustomerID: input.polarCustomerID,
|
avatarUrl: group[0].user.avatarUrl,
|
||||||
};
|
discriminator: group[0].user.discriminator,
|
||||||
}
|
polarCustomerID: group[0].user.polarCustomerID,
|
||||||
|
steamAccounts: !group[0].steam ?
|
||||||
|
[] :
|
||||||
|
group.map((row) => ({
|
||||||
|
id: row.steam!.id,
|
||||||
|
userID: row.steam!.userID,
|
||||||
|
steamID: row.steam!.steamID,
|
||||||
|
lastSeen: row.steam!.lastSeen,
|
||||||
|
avatarUrl: row.steam!.avatarUrl,
|
||||||
|
lastGame: row.steam!.lastGame,
|
||||||
|
username: row.steam!.username,
|
||||||
|
countryCode: row.steam!.countryCode,
|
||||||
|
steamEmail: row.steam!.steamEmail,
|
||||||
|
personaName: row.steam!.personaName,
|
||||||
|
limitation: row.steam!.limitation,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return result[0]
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
export const remove = fn(Info.shape.id, (id) =>
|
export const remove = fn(Info.shape.id, (id) =>
|
||||||
useTransaction(async (tx) => {
|
useTransaction(async (tx) => {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export namespace AccountApi {
|
|||||||
"User not found",
|
"User not found",
|
||||||
);
|
);
|
||||||
|
|
||||||
const { id, email, name, polarCustomerID, avatarUrl, discriminator } = currentUser
|
const { id, email, name, polarCustomerID, avatarUrl, discriminator, steamAccounts } = currentUser
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
data: {
|
data: {
|
||||||
@@ -58,6 +58,7 @@ export namespace AccountApi {
|
|||||||
email,
|
email,
|
||||||
teams,
|
teams,
|
||||||
avatarUrl,
|
avatarUrl,
|
||||||
|
steamAccounts,
|
||||||
discriminator,
|
discriminator,
|
||||||
polarCustomerID,
|
polarCustomerID,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ type OauthUser = {
|
|||||||
console.log("STORAGE", process.env.STORAGE)
|
console.log("STORAGE", process.env.STORAGE)
|
||||||
|
|
||||||
const app = issuer({
|
const app = issuer({
|
||||||
select: Select(),
|
select: Select({
|
||||||
|
providers: {
|
||||||
|
machine: {
|
||||||
|
hide: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
//TODO: Create our own Storage
|
//TODO: Create our own Storage
|
||||||
storage: MemoryStorage({
|
storage: MemoryStorage({
|
||||||
persist: process.env.STORAGE //"/tmp/persist.json",
|
persist: process.env.STORAGE //"/tmp/persist.json",
|
||||||
@@ -122,7 +128,7 @@ const app = issuer({
|
|||||||
longitude
|
longitude
|
||||||
},
|
},
|
||||||
//FIXME: Make this better
|
//FIXME: Make this better
|
||||||
userID: null
|
// userID: null
|
||||||
})
|
})
|
||||||
return ctx.subject("machine", {
|
return ctx.subject("machine", {
|
||||||
machineID,
|
machineID,
|
||||||
|
|||||||
@@ -33,19 +33,21 @@ export function useStorage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
import { createEffect } from "solid-js";
|
import { createEffect } from "solid-js";
|
||||||
import { useOpenAuth } from "@openauthjs/solid"
|
|
||||||
import { Team } from "@nestri/core/team/index";
|
import { Team } from "@nestri/core/team/index";
|
||||||
|
import { useOpenAuth } from "@openauthjs/solid";
|
||||||
|
import { Steam } from "@nestri/core/steam/index";
|
||||||
import { createInitializedContext } from "../common/context";
|
import { createInitializedContext } from "../common/context";
|
||||||
|
|
||||||
type Storage = {
|
type Storage = {
|
||||||
accounts: Record<string, {
|
accounts: Record<string, {
|
||||||
id: string
|
id: string
|
||||||
|
name: string;
|
||||||
email: string
|
email: string
|
||||||
avatarUrl?: string
|
avatarUrl?: string
|
||||||
discriminator: number
|
|
||||||
name: string;
|
|
||||||
polarCustomerID: string;
|
|
||||||
teams: Team.Info[];
|
teams: Team.Info[];
|
||||||
|
discriminator: number
|
||||||
|
polarCustomerID: string;
|
||||||
|
steamAccounts: Steam.Info[];
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user