From 5b5ad23f66d5393eaa5ab59481fe13c627f1e73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesva=CC=88rd?= Date: Fri, 12 Jan 2024 11:31:46 +0100 Subject: [PATCH] web & sdk: improved sdk (better failover and batching) --- .gitignore | 1 + apps/test/src/pages/_app.tsx | 3 +- apps/test/src/pages/test.tsx | 44 ++ .../migration.sql | 3 + .../migration.sql | 9 + apps/web/prisma/schema.prisma | 12 +- apps/web/src/components/Syntax.tsx | 6 +- apps/web/src/components/clients/table.tsx | 13 +- .../src/components/forms/InputWithLabel.tsx | 4 +- apps/web/src/modals/AddClient.tsx | 93 ++- apps/web/src/modals/EditClient.tsx | 15 +- apps/web/src/pages/api/sdk/batch.ts | 238 ++++++++ apps/web/src/pages/api/sdk/events.ts | 5 +- .../api/sdk/profiles/[profileId]/decrement.ts | 5 +- .../api/sdk/profiles/[profileId]/increment.ts | 5 +- .../api/sdk/profiles/[profileId]/index.ts | 5 +- apps/web/src/pages/api/sdk/profiles/index.ts | 26 +- apps/web/src/server/api/routers/client.ts | 6 +- apps/web/src/server/auth.ts | 23 +- packages/sdk-native/index.ts | 9 +- packages/sdk-web/index.ts | 70 ++- packages/sdk/index.ts | 575 ++++++++++-------- packages/sdk/index_old.ts | 360 +++++++++++ packages/types/index.ts | 109 +++- tooling/publish/publish.ts | 1 + tooling/typescript/tsup.config.json | 3 +- 26 files changed, 1266 insertions(+), 377 deletions(-) create mode 100644 apps/web/prisma/migrations/20240110151531_add_cors_settings_on_client/migration.sql create mode 100644 apps/web/prisma/migrations/20240112083054_add_failed_events/migration.sql create mode 100644 apps/web/src/pages/api/sdk/batch.ts create mode 100644 packages/sdk/index_old.ts diff --git a/.gitignore b/.gitignore index 193e7fdd..8303cd42 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore packages/sdk/profileId.txt packages/sdk/test.ts +dump.sql # Logs diff --git a/apps/test/src/pages/_app.tsx b/apps/test/src/pages/_app.tsx index 3a6c316e..a27e8894 100644 --- a/apps/test/src/pages/_app.tsx +++ b/apps/test/src/pages/_app.tsx @@ -3,10 +3,11 @@ import { mixan } from '@/analytics'; import type { AppProps } from 'next/app'; import { useRouter } from 'next/router'; +mixan.init(); + export default function MyApp({ Component, pageProps }: AppProps) { const router = useRouter(); useEffect(() => { - mixan.init(); return router.events.on('routeChangeComplete', () => { mixan.screenView(); }); diff --git a/apps/test/src/pages/test.tsx b/apps/test/src/pages/test.tsx index 8d670b4e..300908d5 100644 --- a/apps/test/src/pages/test.tsx +++ b/apps/test/src/pages/test.tsx @@ -1,9 +1,53 @@ +import { mixan } from '@/analytics'; import Link from 'next/link'; export default function Test() { return (
Home + + + +
); } diff --git a/apps/web/prisma/migrations/20240110151531_add_cors_settings_on_client/migration.sql b/apps/web/prisma/migrations/20240110151531_add_cors_settings_on_client/migration.sql new file mode 100644 index 00000000..cded98e8 --- /dev/null +++ b/apps/web/prisma/migrations/20240110151531_add_cors_settings_on_client/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "clients" ADD COLUMN "cors" TEXT NOT NULL DEFAULT '*', +ALTER COLUMN "secret" DROP NOT NULL; diff --git a/apps/web/prisma/migrations/20240112083054_add_failed_events/migration.sql b/apps/web/prisma/migrations/20240112083054_add_failed_events/migration.sql new file mode 100644 index 00000000..768fc013 --- /dev/null +++ b/apps/web/prisma/migrations/20240112083054_add_failed_events/migration.sql @@ -0,0 +1,9 @@ +-- CreateTable +CREATE TABLE "event_failed" ( + "id" UUID NOT NULL DEFAULT gen_random_uuid(), + "data" JSONB NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "event_failed_pkey" PRIMARY KEY ("id") +); diff --git a/apps/web/prisma/schema.prisma b/apps/web/prisma/schema.prisma index c96479f5..4d298835 100644 --- a/apps/web/prisma/schema.prisma +++ b/apps/web/prisma/schema.prisma @@ -90,14 +90,24 @@ model Profile { @@map("profiles") } +model EventFailed { + id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid + data Json + createdAt DateTime @default(now()) + updatedAt DateTime @default(now()) @updatedAt + + @@map("event_failed") +} + model Client { id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid name String - secret String + secret String? project_id String @db.Uuid project Project @relation(fields: [project_id], references: [id]) organization_id String @db.Uuid organization Organization @relation(fields: [organization_id], references: [id]) + cors String @default("*") createdAt DateTime @default(now()) updatedAt DateTime @default(now()) @updatedAt diff --git a/apps/web/src/components/Syntax.tsx b/apps/web/src/components/Syntax.tsx index c353bddc..347df66b 100644 --- a/apps/web/src/components/Syntax.tsx +++ b/apps/web/src/components/Syntax.tsx @@ -9,5 +9,9 @@ interface SyntaxProps { } export default function Syntax({ code }: SyntaxProps) { - return {code}; + return ( + + {code} + + ); } diff --git a/apps/web/src/components/clients/table.tsx b/apps/web/src/components/clients/table.tsx index 440e8dbb..b6b45453 100644 --- a/apps/web/src/components/clients/table.tsx +++ b/apps/web/src/components/clients/table.tsx @@ -23,17 +23,26 @@ export const columns: ColumnDef[] = [ accessorKey: 'id', header: 'Client ID', }, + { + accessorKey: 'cors', + header: 'Cors', + }, { accessorKey: 'secret', header: 'Secret', - cell: () =>
Hidden
, + cell: (info) => + info.getValue() ? ( +
Hidden
+ ) : ( + 'None' + ), }, { accessorKey: 'createdAt', header: 'Created at', cell({ row }) { const date = row.original.createdAt; - return
{formatDate(date)}
; + return formatDate(date); }, }, { diff --git a/apps/web/src/components/forms/InputWithLabel.tsx b/apps/web/src/components/forms/InputWithLabel.tsx index e9f0c461..47df69df 100644 --- a/apps/web/src/components/forms/InputWithLabel.tsx +++ b/apps/web/src/components/forms/InputWithLabel.tsx @@ -9,9 +9,9 @@ type InputWithLabelProps = InputProps & { }; export const InputWithLabel = forwardRef( - ({ label, ...props }, ref) => { + ({ label, className, ...props }, ref) => { return ( -
+
diff --git a/apps/web/src/modals/AddClient.tsx b/apps/web/src/modals/AddClient.tsx index 2e4c292a..9366b818 100644 --- a/apps/web/src/modals/AddClient.tsx +++ b/apps/web/src/modals/AddClient.tsx @@ -1,8 +1,10 @@ import { ButtonContainer } from '@/components/ButtonContainer'; import { InputWithLabel } from '@/components/forms/InputWithLabel'; import { Button } from '@/components/ui/button'; +import { Checkbox } from '@/components/ui/checkbox'; import { Combobox } from '@/components/ui/combobox'; import { Label } from '@/components/ui/label'; +import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { toast } from '@/components/ui/use-toast'; import { useOrganizationParams } from '@/hooks/useOrganizationParams'; import { useRefetchActive } from '@/hooks/useRefetchActive'; @@ -11,7 +13,7 @@ import { clipboard } from '@/utils/clipboard'; import { zodResolver } from '@hookform/resolvers/zod'; import { Copy } from 'lucide-react'; import dynamic from 'next/dynamic'; -import { Controller, useForm } from 'react-hook-form'; +import { Controller, useForm, useWatch } from 'react-hook-form'; import { z } from 'zod'; import { popModal } from '.'; @@ -21,6 +23,8 @@ const Syntax = dynamic(import('@/components/Syntax')); const validator = z.object({ name: z.string().min(1, 'Required'), + cors: z.string().min(1, 'Required'), + withCors: z.boolean(), projectId: z.string().min(1, 'Required'), }); @@ -46,12 +50,29 @@ export default function CreateProject() { resolver: zodResolver(validator), defaultValues: { name: '', + cors: '*', projectId: '', + withCors: true, }, }); + const withCors = useWatch({ + control, + name: 'withCors', + }); + if (mutation.isSuccess && mutation.data) { - const { clientId, clientSecret } = mutation.data; + const { clientId, clientSecret, cors } = mutation.data; + const snippet = clientSecret + ? `const mixan = new Mixan({ + clientId: "${clientId}", + // Avoid using this on web, rely on cors settings instead + // Mostly for react-native and node/backend + clientSecret: "${clientSecret}", +})` + : `const mixan = new Mixan({ + clientId: "${clientId}", +})`; return ( @@ -60,6 +81,13 @@ export default function CreateProject() { so keep it safe 🫣

+ - + {clientSecret && ( + + )}
-
- +
+
@@ -114,6 +139,36 @@ export default function CreateProject() { {...register('name')} className="mb-4" /> + + ( + + )} + /> + {withCors && ( + <> + +
+ Restrict access by domain names (include https://) +
+ + )} ; @@ -43,6 +44,7 @@ export default function EditClient({ id }: EditClientProps) { defaultValues: { id: '', name: '', + cors: '', }, }); @@ -60,7 +62,18 @@ export default function EditClient({ id }: EditClientProps) { mutation.mutate(values); })} > - +
+ + +