Merge pull request #2 from lindesvard/prepare-beta-launch

Prepare beta launch
This commit is contained in:
Carl-Gerhard Lindesvärd
2024-03-12 09:04:21 +01:00
committed by GitHub
37 changed files with 415 additions and 198 deletions

View File

@@ -1,10 +1,12 @@
import { LogoSquare } from '@/components/Logo'; import { LogoSquare } from '@/components/Logo';
import { ProjectCard } from '@/components/projects/project-card'; import { ProjectCard } from '@/components/projects/project-card';
import { notFound, redirect } from 'next/navigation';
import { import {
getOrganizationBySlug, getOrganizationBySlug,
getProjectsByOrganizationSlug, getProjectsByOrganizationSlug,
isWaitlistUserAccepted,
} from '@openpanel/db'; } from '@openpanel/db';
import { notFound, redirect } from 'next/navigation';
import { CreateProject } from './create-project'; import { CreateProject } from './create-project';
@@ -25,18 +27,21 @@ export default async function Page({ params: { organizationId } }: PageProps) {
} }
if (process.env.BLOCK) { if (process.env.BLOCK) {
return ( const isAccepted = await isWaitlistUserAccepted();
<div className="flex items-center justify-center h-screen"> if (!isAccepted) {
<div className="max-w-lg w-full"> return (
<LogoSquare className="w-20 md:w-28 mb-8" /> <div className="flex items-center justify-center h-screen">
<h1 className="font-medium text-3xl">Not quite there yet</h1> <div className="max-w-lg w-full">
<div className="text-lg"> <LogoSquare className="w-20 md:w-28 mb-8" />
We're still working on Openpanel, but we're not quite there yet. <h1 className="font-medium text-3xl">Not quite there yet</h1>
We'll let you know when we're ready to go! <div className="text-lg">
We're still working on Openpanel, but we're not quite there yet.
We'll let you know when we're ready to go!
</div>
</div> </div>
</div> </div>
</div> );
); }
} }
if (projects.length === 0) { if (projects.length === 0) {

View File

@@ -1,27 +1,30 @@
// import { CreateOrganization } from '@clerk/nextjs'; // import { CreateOrganization } from '@clerk/nextjs';
import { LogoSquare } from '@/components/Logo'; import { LogoSquare } from '@/components/Logo';
import { getCurrentOrganizations } from '@openpanel/db';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import { getCurrentOrganizations, isWaitlistUserAccepted } from '@openpanel/db';
import { CreateOrganization } from './create-organization'; import { CreateOrganization } from './create-organization';
export default async function Page() { export default async function Page() {
const organizations = await getCurrentOrganizations(); const organizations = await getCurrentOrganizations();
if (process.env.BLOCK) { if (process.env.BLOCK) {
return ( const isAccepted = await isWaitlistUserAccepted();
<div className="flex items-center justify-center h-screen"> if (!isAccepted) {
<div className="max-w-lg w-full"> return (
<LogoSquare className="w-20 md:w-28 mb-8" /> <div className="flex items-center justify-center h-screen">
<h1 className="font-medium text-3xl">Not quite there yet</h1> <div className="max-w-lg w-full">
<div className="text-lg"> <LogoSquare className="w-20 md:w-28 mb-8" />
We're still working on Openpanel, but we're not quite there yet. <h1 className="font-medium text-3xl">Not quite there yet</h1>
We'll let you know when we're ready to go! <div className="text-lg">
We're still working on Openpanel, but we're not quite there yet.
We'll let you know when we're ready to go!
</div>
</div> </div>
</div> </div>
</div> );
); }
} }
if (organizations.length > 0) { if (organizations.length > 0) {

View File

@@ -1,35 +1,5 @@
FROM --platform=linux/amd64 node:20-slim AS base FROM --platform=linux/amd64 node:20-slim AS base
ARG NEXT_PUBLIC_DASHBOARD_URL
ENV NEXT_PUBLIC_DASHBOARD_URL=$NEXT_PUBLIC_DASHBOARD_URL
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
ARG DATABASE_URL
ENV DATABASE_URL=$DATABASE_URL
ARG CLICKHOUSE_DB
ENV CLICKHOUSE_DB=$CLICKHOUSE_DB
ARG CLICKHOUSE_PASSWORD
ENV CLICKHOUSE_PASSWORD=$CLICKHOUSE_PASSWORD
ARG CLICKHOUSE_URL
ENV CLICKHOUSE_URL=$CLICKHOUSE_URL
ARG CLICKHOUSE_USER
ENV CLICKHOUSE_USER=$CLICKHOUSE_USER
ARG REDIS_URL
ENV REDIS_URL=$REDIS_URL
ARG NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
ENV NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=$NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
ARG CLERK_SECRET_KEY
ENV CLERK_SECRET_KEY=$CLERK_SECRET_KEY
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
@@ -50,14 +20,7 @@ WORKDIR /app
COPY package.json package.json COPY package.json package.json
COPY pnpm-lock.yaml pnpm-lock.yaml COPY pnpm-lock.yaml pnpm-lock.yaml
COPY pnpm-workspace.yaml pnpm-workspace.yaml COPY pnpm-workspace.yaml pnpm-workspace.yaml
COPY apps/public/package.json apps/public/package.json COPY apps/docs/package.json apps/docs/package.json
COPY packages/db/package.json packages/db/package.json
COPY packages/redis/package.json packages/redis/package.json
COPY packages/queue/package.json packages/queue/package.json
COPY packages/common/package.json packages/common/package.json
COPY packages/constants/package.json packages/constants/package.json
COPY packages/validation/package.json packages/validation/package.json
COPY packages/sdk/package.json packages/sdk/package.json
# BUILD # BUILD
FROM base AS build FROM base AS build
@@ -67,9 +30,8 @@ RUN pnpm install --frozen-lockfile --ignore-scripts
WORKDIR /app WORKDIR /app
COPY apps apps COPY apps apps
COPY packages packages RUN mkdir packages
COPY tooling tooling COPY tooling tooling
RUN pnpm db:codegen
WORKDIR /app/apps/public WORKDIR /app/apps/public
RUN pnpm run build RUN pnpm run build
@@ -86,27 +48,11 @@ FROM base AS runner
COPY --from=build /app/package.json /app/package.json COPY --from=build /app/package.json /app/package.json
COPY --from=prod /app/node_modules /app/node_modules COPY --from=prod /app/node_modules /app/node_modules
# Apps # Apps
COPY --from=build /app/apps/public /app/apps/public COPY --from=build /app/apps/docs /app/apps/docs
# Apps node_modules # Apps node_modules
COPY --from=prod /app/apps/public/node_modules /app/apps/public/node_modules COPY --from=prod /app/apps/docs/node_modules /app/apps/docs/node_modules
# Packages
COPY --from=build /app/packages/db /app/packages/db
COPY --from=build /app/packages/redis /app/packages/redis
COPY --from=build /app/packages/common /app/packages/common
COPY --from=build /app/packages/queue /app/packages/queue
COPY --from=build /app/packages/constants /app/packages/constants
COPY --from=build /app/packages/validation /app/packages/validation
COPY --from=build /app/packages/sdk /app/packages/sdk
# Packages node_modules
COPY --from=prod /app/packages/db/node_modules /app/packages/db/node_modules
COPY --from=prod /app/packages/redis/node_modules /app/packages/redis/node_modules
COPY --from=prod /app/packages/common/node_modules /app/packages/common/node_modules
COPY --from=prod /app/packages/queue/node_modules /app/packages/queue/node_modules
COPY --from=prod /app/packages/validation/node_modules /app/packages/validation/node_modules
RUN pnpm db:codegen WORKDIR /app/apps/docs
WORKDIR /app/apps/public
EXPOSE 3000 EXPOSE 3000

View File

@@ -0,0 +1,15 @@
interface Props {
src: string;
isDark?: boolean;
}
export function BrandLogo({ src, isDark }: Props) {
if (isDark) {
return (
<div className="w-9 h-9 p-1 rounded-full bg-white">
<img className="w-full h-full object-contain" src={src} />
</div>
);
}
return <img className="w-9 h-9 object-contain" src={src} />;
}

View File

@@ -1,14 +1,21 @@
{ {
"index": "Get Started", "index": "Get Started",
"-- Implementation": { "-- Frameworks": {
"type": "separator", "type": "separator",
"title": "Implementation" "title": "Frameworks"
}, },
"script": "Script", "script": "Script",
"javascript": "Javascript SDK",
"nextjs": "Next.js", "nextjs": "Next.js",
"react": "React", "react": "React",
"react-native": "React-Native", "react-native": "React-Native",
"remix": "Remix", "remix": "Remix",
"vue": "Vue" "vue": "Vue",
"astro": "Astro",
"node": "Node (backend)",
"-- Others": {
"type": "separator",
"title": "Others"
},
"javascript": "Javascript SDK",
"web": "Web SDK"
} }

View File

@@ -0,0 +1,5 @@
import Link from 'next/link';
# Astro
You can use <Link href="/docs/script">script tag</Link> or <Link href="/docs/web">Web SDK</Link> to track events in Astro.

View File

@@ -1,4 +1,5 @@
import { Card, Cards } from 'nextra/components'; import { Card, Cards } from 'nextra/components';
import { BrandLogo } from 'src/components/brand-logo';
# Get started # Get started
@@ -7,22 +8,16 @@ Create an account on [Openpanel](https://openpanel.dev) and setup your first pro
<Cards> <Cards>
<Card <Card
icon={ icon={
<img <BrandLogo src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/61/HTML5_logo_and_wordmark.svg/240px-HTML5_logo_and_wordmark.svg.png" />
style={{ width: 32, height: 32, objectFit: 'contain' }}
src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/61/HTML5_logo_and_wordmark.svg/240px-HTML5_logo_and_wordmark.svg.png"
/>
} }
title="General / Script" title="HTML / Script"
href="/docs/general" href="/docs/script"
> >
{' '} {' '}
</Card> </Card>
<Card <Card
icon={ icon={
<img <BrandLogo src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png" />
style={{ width: 32, height: 32, objectFit: 'contain' }}
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png"
/>
} }
title="React" title="React"
href="/docs/react" href="/docs/react"
@@ -31,10 +26,7 @@ Create an account on [Openpanel](https://openpanel.dev) and setup your first pro
</Card> </Card>
<Card <Card
icon={ icon={
<img <BrandLogo src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png" />
style={{ width: 32, height: 32, objectFit: 'contain' }}
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/2300px-React-icon.svg.png"
/>
} }
title="React-Native" title="React-Native"
href="/docs/react-native" href="/docs/react-native"
@@ -43,8 +35,8 @@ Create an account on [Openpanel](https://openpanel.dev) and setup your first pro
</Card> </Card>
<Card <Card
icon={ icon={
<img <BrandLogo
style={{ width: 32, height: 32, objectFit: 'contain' }} isDark
src="https://static-00.iconduck.com/assets.00/nextjs-icon-512x512-y563b8iq.png" src="https://static-00.iconduck.com/assets.00/nextjs-icon-512x512-y563b8iq.png"
/> />
} }
@@ -55,8 +47,8 @@ Create an account on [Openpanel](https://openpanel.dev) and setup your first pro
</Card> </Card>
<Card <Card
icon={ icon={
<img <BrandLogo
style={{ width: 32, height: 32, objectFit: 'contain' }} isDark
src="https://www.datocms-assets.com/205/1642515307-square-logo.svg" src="https://www.datocms-assets.com/205/1642515307-square-logo.svg"
/> />
} }
@@ -67,14 +59,23 @@ Create an account on [Openpanel](https://openpanel.dev) and setup your first pro
</Card> </Card>
<Card <Card
icon={ icon={
<img <BrandLogo src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/1024px-Vue.js_Logo_2.svg.png" />
style={{ width: 32, height: 32, objectFit: 'contain' }}
src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/95/Vue.js_Logo_2.svg/1024px-Vue.js_Logo_2.svg.png"
/>
} }
title="Vue" title="Vue"
href="/docs/vue" href="/docs/vue"
> >
{' '} {' '}
</Card> </Card>
<Card
icon={
<BrandLogo
isDark
src="https://astro.build/assets/press/astro-icon-dark.png"
/>
}
title="Astro"
href="/docs/vue"
>
{' '}
</Card>
</Cards> </Cards>

View File

@@ -7,7 +7,7 @@ import SdkConfig from 'src/components/sdk-config.mdx';
# Javascript SDK # Javascript SDK
This is the base SDK for Openpanel. All other SDKs are built on top of this one. This is the base SDK for Openpanel. All other SDKs/frameworks are built on top of this one.
## Installation ## Installation
@@ -21,9 +21,9 @@ pnpm install @openpanel/sdk
### Initialize ### Initialize
```tsx ```tsx
import { Openpanel } from '@openpanel/sdk'; import { OpenpanelSdk } from '@openpanel/sdk';
const op = new Openpanel({ const op = new OpenpanelSdk({
url: 'https://api.openpanel.dev', url: 'https://api.openpanel.dev',
clientId: '{YOUR_CLIENT_ID}', clientId: '{YOUR_CLIENT_ID}',
// mostly for backend and apps that can't rely on CORS // mostly for backend and apps that can't rely on CORS
@@ -84,10 +84,8 @@ Keep track of your users by identifying them with a unique id. This is a good fe
<PersonalDataWarning /> <PersonalDataWarning />
```typescript ```typescript
import { setProfileId } from '@openpanel/nextjs';
const profileId = '123'; const profileId = '123';
setProfileId(profileId); op.setProfileId(profileId);
``` ```
#### Additional data #### Additional data
@@ -97,10 +95,8 @@ This method does the same as `setProfileId` but also allows you to update the pr
<PersonalDataWarning /> <PersonalDataWarning />
```typescript ```typescript
import { setProfile } from '@openpanel/nextjs';
const profileId = '123'; const profileId = '123';
setProfile({ op.setProfile({
profileId, profileId,
// firstName?: string; // firstName?: string;
// lastName?: string; // lastName?: string;
@@ -115,13 +111,11 @@ setProfile({
Increment a property on the profile. Increment a property on the profile.
```typescript ```typescript
import { increment } from '@openpanel/nextjs';
// Increment by 1 // Increment by 1
increment('app_opened'); op.increment('app_opened');
// Increment by 5 // Increment by 5
increment('app_opened', 5); op.increment('app_opened', 5);
``` ```
#### Decrement property #### Decrement property
@@ -129,11 +123,17 @@ increment('app_opened', 5);
Decrement a property on the profile. Decrement a property on the profile.
```typescript ```typescript
import { decrement } from '@openpanel/nextjs';
// Increment by 1 // Increment by 1
decrement('app_opened'); op.decrement('app_opened');
// Increment by 5 // Increment by 5
decrement('app_opened', 5); op.decrement('app_opened', 5);
```
#### Clear / Logout
Clear the profile id and all the data.
```typescript
op.clear();
``` ```

View File

@@ -7,7 +7,9 @@ import SdkConfig from 'src/components/sdk-config.mdx';
# Next.js # Next.js
Keep in mind that all tracking here happens on the client! If you want to track server-side events, you should use the <Link href="/docs/node">node SDK</Link> 👀. Keep in mind that all tracking here happens on the client!
Read more about server side tracking in the [Server Side Tracking](#track-server-events) section.
## Installation ## Installation
@@ -170,3 +172,32 @@ decrement('app_opened');
// Increment by 5 // Increment by 5
decrement('app_opened', 5); decrement('app_opened', 5);
``` ```
#### Clear / Logout
Clear the profile id and all the data.
```typescript
import { clear } from '@openpanel/nextjs';
clear();
```
### Track server events
If you want to track server-side events, you should create an instance of our Javascript SDK. It's exported from `@openpanel/nextjs`
```typescript
import { OpenpanelSdk } from '@openpanel/nextjs';
const opServer = new OpenpanelSdk({
url: 'https://api.openpanel.dev',
clientId: '{YOUR_CLIENT_ID}',
clientSecret: '{YOUR_CLIENT_SECRET}',
});
opServer.event('my_server_event', { ok: '✅' });
// Pass `profileId` to track events for a specific user
opServer.event('my_server_event', { profileId: '123', ok: '✅' });
```

View File

@@ -0,0 +1,5 @@
import Link from 'next/link';
# Node
Use <Link href="/docs/javascript">Javascript SDK</Link> to track events in Node.

View File

@@ -194,3 +194,11 @@ op.decrement('app_opened');
// Increment by 5 // Increment by 5
op.decrement('app_opened', 5); op.decrement('app_opened', 5);
``` ```
#### Clear / Logout
Clear the profile id and all the data.
```typescript
op.clear();
```

View File

@@ -2,4 +2,4 @@ import Link from 'next/link';
# React # React
Use <Link href="/docs/general">script tag</Link> or <Link href="/docs/general">Javascript SDK</Link> for now. We'll add a dedicated react sdk soon. Use <Link href="/docs/script">script tag</Link> or <Link href="/docs/web">Web SDK</Link> for now. We'll add a dedicated react sdk soon.

View File

@@ -2,4 +2,4 @@ import Link from 'next/link';
# Remix # Remix
Use <Link href="/docs/general">script tag</Link> or <Link href="/docs/general">Javascript SDK</Link> for now. We'll add a dedicated react sdk soon. Use <Link href="/docs/script">script tag</Link> or <Link href="/docs/web">Web SDK</Link> for now. We'll add a dedicated remix sdk soon.

View File

@@ -104,6 +104,14 @@ window.op('decrement', 'app_opened');
window.op('decrement', 'app_opened', 5); window.op('decrement', 'app_opened', 5);
``` ```
#### Clear / Logout
Clear the profile id and all the data.
```typescript
window.op('clear');
```
### Typescript ### Typescript
Is your IDE mad at you for not using typescript? We got you covered. Is your IDE mad at you for not using typescript? We got you covered.

View File

@@ -2,4 +2,4 @@ import Link from 'next/link';
# Vue # Vue
Use <Link href="/docs/general">script tag</Link> or <Link href="/docs/general">Javascript SDK</Link> for now. We'll add a dedicated react sdk soon. Use <Link href="/docs/script">script tag</Link> or <Link href="/docs/web">Web SDK</Link> for now. We'll add a dedicated react sdk soon.

View File

@@ -0,0 +1,138 @@
import Link from 'next/link';
import { Callout, Steps, Tabs } from 'nextra/components';
import { DeviceIdWarning } from 'src/components/device-id-warning';
import { PersonalDataWarning } from 'src/components/personal-data-warning';
import SdkConfig from 'src/components/sdk-config.mdx';
# Web SDK
This is a wrapper of <Link href="/docs/javascript">Javascript SDK</Link>. It's a simple way to use the Openpanel SDK in your web application.
## Installation
<Steps>
### Install dependencies
```bash
pnpm install @openpanel/web
```
### Initialize
```tsx
import { Openpanel } from '@openpanel/web';
const op = new Openpanel({
url: 'https://api.openpanel.dev',
clientId: '{YOUR_CLIENT_ID}',
trackScreenViews: true,
// trackAttributes: true,
// trackOutgoingLinks: true,
});
```
#### Config
<SdkConfig />
### Ready!
You're now ready to use the library.
```typescript
// Sends an event with payload foo: bar
op.event('my_event', { foo: 'bar' });
// Identify with profile id
op.setProfileId('123');
// or with additional data
op.setProfile({
profileId: '123',
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@openpanel.dev',
});
// Increment a property
op.increment('app_opened'); // increment by 1
op.increment('app_opened', 5); // increment by 5
// Decrement a property
op.decrement('app_opened'); // decrement by 1
op.decrement('app_opened', 5); // decrement by 5
```
</Steps>
## Usage
### Track event
```typescript
op.event('my_event', { foo: 'bar' });
```
### Identify
#### Set Profile Id
Keep track of your users by identifying them with a unique id. This is a good features if you have things behind a login and want to track user behavior.
<PersonalDataWarning />
```typescript
const profileId = '123';
op.setProfileId(profileId);
```
#### Additional data
This method does the same as `setProfileId` but also allows you to update the profile with additional data.
<PersonalDataWarning />
```typescript
const profileId = '123';
op.setProfile({
profileId,
// firstName?: string;
// lastName?: string;
// email?: string;
// avatar?: string;
// properties?: Record<string, unknown>;
});
```
#### Increment property
Increment a property on the profile.
```typescript
// Increment by 1
op.increment('app_opened');
// Increment by 5
op.increment('app_opened', 5);
```
#### Decrement property
Decrement a property on the profile.
```typescript
// Increment by 1
op.decrement('app_opened');
// Increment by 5
op.decrement('app_opened', 5);
```
#### Clear / Logout
Clear the profile id and all the data.
```typescript
op.clear();
```

4
captain-definition-docs Normal file
View File

@@ -0,0 +1,4 @@
{
"schemaVersion": 2,
"dockerfilePath": "./apps/docs/Dockerfile"
}

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "waitlist" ADD COLUMN "accepted" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -153,6 +153,7 @@ model Waitlist {
email String @unique email String @unique
createdAt DateTime @default(now()) createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt updatedAt DateTime @default(now()) @updatedAt
accepted Boolean @default(false)
@@map("waitlist") @@map("waitlist")
} }

View File

@@ -1,6 +1,8 @@
import { auth, clerkClient } from '@clerk/nextjs'; import { auth, clerkClient } from '@clerk/nextjs';
import type { User } from '@clerk/nextjs/dist/types/server'; import type { User } from '@clerk/nextjs/dist/types/server';
import { db } from '../prisma-client';
export function transformUser(user: User) { export function transformUser(user: User) {
return { return {
name: `${user.firstName} ${user.lastName}`, name: `${user.firstName} ${user.lastName}`,
@@ -22,3 +24,18 @@ export async function getCurrentUser() {
export async function getUserById(id: string) { export async function getUserById(id: string) {
return clerkClient.users.getUser(id).then(transformUser); return clerkClient.users.getUser(id).then(transformUser);
} }
export async function isWaitlistUserAccepted() {
const user = await getCurrentUser();
const waitlist = await db.waitlist.findFirst({
where: {
email: user?.email,
},
});
if (!waitlist) {
return false;
}
return waitlist.accepted;
}

View File

@@ -2,12 +2,23 @@ import Script from 'next/script';
import type { import type {
OpenpanelEventOptions, OpenpanelEventOptions,
OpenpanelWebOptions, OpenpanelOptions,
PostEventPayload, PostEventPayload,
UpdateProfilePayload, UpdateProfilePayload,
} from '@openpanel/web'; } from '@openpanel/web';
const CDN_URL = 'http://localhost:3002/op.js'; export * from '@openpanel/web';
const CDN_URL = 'https://openpanel.dev/op.js';
declare global {
interface Window {
op: {
q?: [string, ...any[]];
(method: OpenpanelMethods, ...args: any[]): void;
};
}
}
type OpenpanelMethods = type OpenpanelMethods =
| 'ctor' | 'ctor'
@@ -19,7 +30,7 @@ type OpenpanelMethods =
| 'clear'; | 'clear';
declare global { declare global {
interface Window { interface window {
op: { op: {
q?: [string, ...any[]]; q?: [string, ...any[]];
(method: OpenpanelMethods, ...args: any[]): void; (method: OpenpanelMethods, ...args: any[]): void;
@@ -27,7 +38,7 @@ declare global {
} }
} }
type OpenpanelProviderProps = OpenpanelWebOptions & { type OpenpanelProviderProps = OpenpanelOptions & {
profileId?: string; profileId?: string;
cdnUrl?: string; cdnUrl?: string;
}; };

View File

@@ -4,13 +4,11 @@
"module": "index.ts", "module": "index.ts",
"scripts": { "scripts": {
"build": "rm -rf dist && tsup", "build": "rm -rf dist && tsup",
"build-for-openpanel": "pnpm build && cp dist/cdn.global.js ../../apps/public/public/op.js && cp dist/cdn.global.js ../../apps/test/public/op.js",
"lint": "eslint .", "lint": "eslint .",
"format": "prettier --check \"**/*.{mjs,ts,md,json}\"", "format": "prettier --check \"**/*.{mjs,ts,md,json}\"",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@openpanel/sdk": "workspace:*",
"@openpanel/web": "workspace:*" "@openpanel/web": "workspace:*"
}, },
"peerDependencies": { "peerDependencies": {
@@ -20,6 +18,7 @@
"@openpanel/eslint-config": "workspace:*", "@openpanel/eslint-config": "workspace:*",
"@openpanel/prettier-config": "workspace:*", "@openpanel/prettier-config": "workspace:*",
"@openpanel/tsconfig": "workspace:*", "@openpanel/tsconfig": "workspace:*",
"@types/react": "^18.2.20",
"eslint": "^8.48.0", "eslint": "^8.48.0",
"prettier": "^3.0.3", "prettier": "^3.0.3",
"tsup": "^7.2.0", "tsup": "^7.2.0",

View File

@@ -1,6 +1,7 @@
{ {
"extends": "@openpanel/tsconfig/base.json", "extends": "@openpanel/tsconfig/base.json",
"compilerOptions": { "compilerOptions": {
"incremental": false,
"outDir": "dist" "outDir": "dist"
} }
} }

View File

@@ -4,6 +4,6 @@ import config from '@openpanel/tsconfig/tsup.config.json' assert { type: 'json'
export default defineConfig({ export default defineConfig({
...(config as any), ...(config as any),
entry: ['index.ts'], entry: ['index.tsx'],
format: ['cjs', 'esm'], format: ['cjs', 'esm'],
}); });

View File

@@ -2,13 +2,14 @@ import { AppState, Platform } from 'react-native';
import * as Application from 'expo-application'; import * as Application from 'expo-application';
import Constants from 'expo-constants'; import Constants from 'expo-constants';
import type { OpenpanelOptions, PostEventPayload } from '@openpanel/sdk'; import type { OpenpanelSdkOptions, PostEventPayload } from '@openpanel/sdk';
import { Openpanel } from '@openpanel/sdk'; import { OpenpanelSdk } from '@openpanel/sdk';
type OpenpanelNativeOptions = OpenpanelOptions; export * from '@openpanel/sdk';
export type OpenpanelOptions = OpenpanelSdkOptions;
export class OpenpanelNative extends Openpanel<OpenpanelNativeOptions> { export class Openpanel extends OpenpanelSdk<OpenpanelOptions> {
constructor(options: OpenpanelNativeOptions) { constructor(options: OpenpanelOptions) {
super(options); super(options);
this.api.headers['User-Agent'] = Constants.getWebViewUserAgentAsync(); this.api.headers['User-Agent'] = Constants.getWebViewUserAgentAsync();

View File

@@ -1,6 +1,7 @@
{ {
"extends": "@openpanel/tsconfig/sdk.json", "extends": "@openpanel/tsconfig/base.json",
"compilerOptions": { "compilerOptions": {
"incremental": false,
"outDir": "dist" "outDir": "dist"
} }
} }

View File

@@ -2,7 +2,4 @@ import { defineConfig } from 'tsup';
import config from '@openpanel/tsconfig/tsup.config.json' assert { type: 'json' }; import config from '@openpanel/tsconfig/tsup.config.json' assert { type: 'json' };
export default defineConfig({ export default defineConfig(config as any);
...(config as any),
minify: false,
});

View File

@@ -1,5 +1,3 @@
// NEW
export interface OpenpanelEventOptions { export interface OpenpanelEventOptions {
profileId?: string; profileId?: string;
} }
@@ -33,7 +31,7 @@ export interface DecrementProfilePayload {
value: number; value: number;
} }
export interface OpenpanelOptions { export interface OpenpanelSdkOptions {
url: string; url: string;
clientId: string; clientId: string;
clientSecret?: string; clientSecret?: string;
@@ -127,7 +125,9 @@ function createApi(_url: string) {
}; };
} }
export class Openpanel<Options extends OpenpanelOptions = OpenpanelOptions> { export class OpenpanelSdk<
Options extends OpenpanelSdkOptions = OpenpanelSdkOptions,
> {
public options: Options; public options: Options;
public api: ReturnType<typeof createApi>; public api: ReturnType<typeof createApi>;
private state: OpenpanelState = { private state: OpenpanelState = {

View File

@@ -1 +0,0 @@
f97a3167-8dc6-4bed-923b-3d118c544006

View File

@@ -1,6 +1,7 @@
{ {
"extends": "@openpanel/tsconfig/sdk.json", "extends": "@openpanel/tsconfig/base.json",
"compilerOptions": { "compilerOptions": {
"incremental": false,
"outDir": "dist" "outDir": "dist"
} }
} }

View File

@@ -1,4 +1,4 @@
import { OpenpanelWeb as Openpanel } from './index'; import { Openpanel } from './index';
declare global { declare global {
interface Window { interface Window {

View File

@@ -1,9 +1,9 @@
import type { OpenpanelOptions, PostEventPayload } from '@openpanel/sdk'; import type { OpenpanelSdkOptions, PostEventPayload } from '@openpanel/sdk';
import { Openpanel } from '@openpanel/sdk'; import { OpenpanelSdk } from '@openpanel/sdk';
export * from '@openpanel/sdk'; export * from '@openpanel/sdk';
export type OpenpanelWebOptions = OpenpanelOptions & { export type OpenpanelOptions = OpenpanelSdkOptions & {
trackOutgoingLinks?: boolean; trackOutgoingLinks?: boolean;
trackScreenViews?: boolean; trackScreenViews?: boolean;
trackAttributes?: boolean; trackAttributes?: boolean;
@@ -16,10 +16,10 @@ function toCamelCase(str: string) {
); );
} }
export class OpenpanelWeb extends Openpanel<OpenpanelWebOptions> { export class Openpanel extends OpenpanelSdk<OpenpanelOptions> {
private lastPath = ''; private lastPath = '';
constructor(options: OpenpanelWebOptions) { constructor(options: OpenpanelOptions) {
super(options); super(options);
if (!this.isServer()) { if (!this.isServer()) {

View File

@@ -1,6 +1,7 @@
{ {
"extends": "@openpanel/tsconfig/sdk.json", "extends": "@openpanel/tsconfig/base.json",
"compilerOptions": { "compilerOptions": {
"incremental": false,
"outDir": "dist" "outDir": "dist"
} }
} }

9
pnpm-lock.yaml generated
View File

@@ -924,9 +924,6 @@ importers:
packages/sdks/nextjs: packages/sdks/nextjs:
dependencies: dependencies:
'@openpanel/sdk':
specifier: workspace:*
version: link:../sdk
'@openpanel/web': '@openpanel/web':
specifier: workspace:* specifier: workspace:*
version: link:../web version: link:../web
@@ -943,6 +940,9 @@ importers:
'@openpanel/tsconfig': '@openpanel/tsconfig':
specifier: workspace:* specifier: workspace:*
version: link:../../../tooling/typescript version: link:../../../tooling/typescript
'@types/react':
specifier: ^18.2.20
version: 18.2.56
eslint: eslint:
specifier: ^8.48.0 specifier: ^8.48.0
version: 8.56.0 version: 8.56.0
@@ -1152,6 +1152,9 @@ importers:
tooling/publish: tooling/publish:
dependencies: dependencies:
arg:
specifier: ^5.0.2
version: 5.0.2
semver: semver:
specifier: ^7.5.4 specifier: ^7.5.4
version: 7.6.0 version: 7.6.0

View File

@@ -10,6 +10,7 @@
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"arg": "^5.0.2",
"semver": "^7.5.4" "semver": "^7.5.4"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { execSync } from 'node:child_process'; import { execSync } from 'node:child_process';
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import arg from 'arg';
import semver from 'semver'; import semver from 'semver';
const sdkPackages = ['sdk', 'react-native', 'web', 'nextjs']; const sdkPackages = ['sdk', 'react-native', 'web', 'nextjs'];
@@ -24,14 +24,36 @@ function exit(message: string, error?: unknown) {
process.exit(1); process.exit(1);
} }
function main() { function checkUncommittedChanges() {
const [version] = process.argv.slice(2); try {
const changedFiles = execSync('git ls-files --exclude-standard --others')
if (!version) { .toString()
return console.error('Missing version'); .trim();
if (changedFiles !== '') {
throw new Error('Uncommitted changes');
}
execSync('git diff HEAD --exit-code');
console.log('✅ No uncommitted changes');
} catch (error) {
exit('Uncommitted changes', error);
} }
}
if (!semver.valid(version)) { function main() {
checkUncommittedChanges();
const args = arg({
// Types
'--version': String,
'--test': Boolean,
// Aliases
'-v': '--version',
});
const version = args['--version'];
const test = args['--test'];
if (version && !semver.valid(version)) {
return console.error('Version is not valid'); return console.error('Version is not valid');
} }
@@ -51,8 +73,10 @@ function main() {
try { try {
for (const name of sdkPackages) { for (const name of sdkPackages) {
const pkgJson = require(workspacePath(`./packages/${name}/package.json`)); const pkgJson = require(
savePackageJson(workspacePath(`./packages/${name}/package.json`), { workspacePath(`./packages/sdks/${name}/package.json`)
);
savePackageJson(workspacePath(`./packages/sdks/${name}/package.json`), {
...pkgJson, ...pkgJson,
...properties, ...properties,
dependencies: Object.entries(pkgJson.dependencies).reduce( dependencies: Object.entries(pkgJson.dependencies).reduce(
@@ -82,14 +106,16 @@ function main() {
console.log('✅ Built packages'); console.log('✅ Built packages');
try { if (!test) {
for (const name of sdkPackages) { try {
execSync('npm publish --access=public', { for (const name of sdkPackages) {
cwd: workspacePath(`./packages/${name}`), execSync('npm publish --access=public', {
}); cwd: workspacePath(`./packages/sdks/${name}`),
});
}
} catch (error) {
exit('Failed publish packages', error);
} }
} catch (error) {
exit('Failed publish packages', error);
} }
console.log('✅ All done!'); console.log('✅ All done!');

View File

@@ -1,20 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"composite": false,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"allowImportingTsExtensions": false,
"noEmit": false
}
}