-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1300 from dubinc/referrals-tokens
Dub Embed Widget
- Loading branch information
Showing
124 changed files
with
2,944 additions
and
1,909 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: "Deploy embed script" | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- "packages/embeds/core/**" | ||
workflow_dispatch: | ||
|
||
jobs: | ||
deploy: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- name: Install dependencies & build | ||
run: pnpm --filter @dub/embed-core build | ||
|
||
# - name: Deploy to Cloudflare Pages (https://www.dubcdn.com/embed/script.js) | ||
# uses: cloudflare/wrangler-action@v3 | ||
# with: | ||
# apiToken: ${{ secrets.CLOUDFLARE_PAGES_API_KEY }} | ||
# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | ||
# command: pages deploy dist/embed/script.js --project-name=dub-cdn --commit-dirty=true | ||
# workingDirectory: packages/embeds/core | ||
# packageManager: pnpm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
name: Publish `@dub/embed-react` | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- "packages/embeds/react/**" | ||
release: | ||
types: [published] | ||
workflow_dispatch: | ||
|
||
jobs: | ||
publish: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
|
||
- name: Setup Node.js | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: "18" | ||
registry-url: "https://registry.npmjs.org" | ||
|
||
- name: Install dependencies | ||
run: pnpm install | ||
|
||
- name: Build | ||
run: pnpm --filter @dub/embed-react build | ||
|
||
- name: Publish | ||
run: pnpm --filter @dub/embed-react publish --no-git-checks | ||
if: github.event.release.prerelease == false | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
|
||
- name: Publish beta | ||
run: pnpm --filter @dub/embed-react publish --no-git-checks --tag beta | ||
if: github.event.release.prerelease == true | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { getAnalytics } from "@/lib/analytics/get-analytics"; | ||
import { calculateEarnings } from "@/lib/api/sales/commission"; | ||
import { withEmbedToken } from "@/lib/embed/auth"; | ||
import { analyticsQuerySchema } from "@/lib/zod/schemas/analytics"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// GET /api/analytics/client - get analytics for the current link | ||
export const GET = withEmbedToken(async ({ link, searchParams, program }) => { | ||
const parsedParams = analyticsQuerySchema | ||
.pick({ | ||
event: true, | ||
start: true, | ||
end: true, | ||
interval: true, | ||
groupBy: true, | ||
timezone: true, | ||
}) | ||
.parse(searchParams); | ||
|
||
const response = await getAnalytics({ | ||
...parsedParams, | ||
linkId: link.id, | ||
}); | ||
|
||
let data; | ||
|
||
if (response instanceof Array) { | ||
data = response.map((item) => { | ||
return { | ||
...item, | ||
earnings: calculateEarnings({ | ||
program, | ||
sales: item.sales ?? 0, | ||
saleAmount: item.saleAmount ?? 0, | ||
}), | ||
}; | ||
}); | ||
} else { | ||
data = { | ||
...response, | ||
earnings: calculateEarnings({ | ||
program, | ||
sales: response.sales, | ||
saleAmount: response.saleAmount, | ||
}), | ||
}; | ||
} | ||
|
||
return NextResponse.json(data); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { withEmbedToken } from "@/lib/embed/auth"; | ||
import { prisma } from "@/lib/prisma"; | ||
import z from "@/lib/zod"; | ||
import { PartnerSaleResponseSchema } from "@/lib/zod/schemas/partners"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// GET /api/embed/sales – get sales for a link from an embed token | ||
export const GET = withEmbedToken(async ({ link }) => { | ||
const sales = await prisma.sale.findMany({ | ||
where: { | ||
linkId: link.id, | ||
}, | ||
select: { | ||
id: true, | ||
amount: true, | ||
earnings: true, | ||
currency: true, | ||
status: true, | ||
createdAt: true, | ||
updatedAt: true, | ||
customer: { | ||
select: { | ||
email: true, | ||
avatar: true, | ||
}, | ||
}, | ||
}, | ||
take: 3, | ||
orderBy: { | ||
createdAt: "desc", | ||
}, | ||
}); | ||
|
||
return NextResponse.json(z.array(PartnerSaleResponseSchema).parse(sales)); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { withEmbedToken } from "@/lib/embed/auth"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// GET /api/embed/token - get the embed token for the given link | ||
export const GET = withEmbedToken(async ({ linkToken }) => { | ||
return NextResponse.json(linkToken); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { getEvents } from "@/lib/analytics/get-events"; | ||
import { calculateEarnings } from "@/lib/api/sales/commission"; | ||
import { withEmbedToken } from "@/lib/embed/auth"; | ||
import { eventsQuerySchema } from "@/lib/zod/schemas/analytics"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// GET /api/events/client - get events for the current link | ||
export const GET = withEmbedToken(async ({ searchParams, program, link }) => { | ||
const parsedParams = eventsQuerySchema | ||
.omit({ | ||
linkId: true, | ||
externalId: true, | ||
domain: true, | ||
root: true, | ||
key: true, | ||
tagId: true, | ||
}) | ||
.parse(searchParams); | ||
|
||
// TODO: | ||
// Replace with sales data | ||
|
||
const response = await getEvents({ | ||
...parsedParams, | ||
linkId: link.id, | ||
}); | ||
|
||
return NextResponse.json( | ||
response.map((item: any) => { | ||
return { | ||
...item, | ||
...(parsedParams.event === "sales" && { | ||
earnings: calculateEarnings({ | ||
program, | ||
sales: item.sales ?? 0, | ||
saleAmount: item.sale?.amount ?? 0, | ||
}), | ||
}), | ||
}; | ||
}), | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { getLinkOrThrow } from "@/lib/api/links/get-link-or-throw"; | ||
import { parseRequestBody } from "@/lib/api/utils"; | ||
import { withWorkspace } from "@/lib/auth"; | ||
import { embedToken } from "@/lib/embed/embed-token"; | ||
import { | ||
createEmbedTokenSchema, | ||
EmbedTokenSchema, | ||
} from "@/lib/zod/schemas/token"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// POST /api/tokens/embed - create a new embed token for the given link | ||
export const POST = withWorkspace( | ||
async ({ workspace, req }) => { | ||
const { linkId } = createEmbedTokenSchema.parse( | ||
await parseRequestBody(req), | ||
); | ||
|
||
await getLinkOrThrow({ linkId, workspaceId: workspace.id }); | ||
|
||
const response = await embedToken.create(linkId); | ||
|
||
return NextResponse.json(EmbedTokenSchema.parse(response), { | ||
status: 201, | ||
}); | ||
}, | ||
{ | ||
requiredPermissions: ["links.write"], | ||
requiredAddOn: "conversion", | ||
}, | ||
); |
27 changes: 27 additions & 0 deletions
27
apps/web/app/api/workspaces/[idOrSlug]/embed-token/route.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { DubApiError } from "@/lib/api/errors"; | ||
import { withWorkspace } from "@/lib/auth"; | ||
import { APP_DOMAIN_WITH_NGROK } from "@dub/utils"; | ||
import { NextResponse } from "next/server"; | ||
|
||
// GET /api/workspaces/[idOrSlug]/embed-token - create a new public embed token for the workspace | ||
export const POST = withWorkspace(async ({ workspace }) => { | ||
const { referralLinkId } = workspace; | ||
|
||
if (!referralLinkId) { | ||
throw new DubApiError({ | ||
code: "bad_request", | ||
message: "Referral link not found for this workspace.", | ||
}); | ||
} | ||
|
||
const token = await fetch(`${APP_DOMAIN_WITH_NGROK}/api/tokens/embed`, { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
Authorization: `Bearer ${process.env.DUB_API_KEY}`, | ||
}, | ||
body: JSON.stringify({ linkId: referralLinkId }), | ||
}).then((res) => res.json()); | ||
|
||
return NextResponse.json(token); | ||
}); |
Oops, something went wrong.