Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
seanboose committed Jun 6, 2024
1 parent 5fe3e8e commit d52ac90
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 112 deletions.
34 changes: 7 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Welcome to Remix!
# DM SDK SSR/CSR API PoC

- [Remix Docs](https://remix.run/docs)
This app is a proof of concept for a couple of ideas on how to unite the CSR and the SSR APIs of the DM SDK.

1. How to allow attribution handlers (click, impress) with the SSR ads. We wrapped the ad info into a class that has click and impression handlers, (de)serialize that class instance to pass it form server state to client state. This allows the same Ad class to be used in both SSR and CSR as long as it's reconstructed with the same values.
2. How to handle JDID in SSR, since we can't store it in localStorage. We provide a cookie that the roots partner must set in their SSR response, and then read that cookie to get the JDID in future requests.

We still need to come up with a way to ensure that roots partners actually set the cookie we provide, since this PoC only *allows* them to do so but doesn't *require* it.

## Development

Expand All @@ -11,28 +16,3 @@ npm run dev
```

This starts your app in development mode, rebuilding assets on file changes.

## Deployment

First, build your app for production:

```sh
npm run build
```

Then run the app in production mode:

```sh
npm start
```

Now you'll need to pick a host to deploy it to.

### DIY

If you're familiar with deploying node applications, the built-in Remix app server is production-ready.

Make sure to deploy the output of `remix build`

- `build/server`
- `build/client`
167 changes: 82 additions & 85 deletions app/fakeSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,116 +3,113 @@ import {nanoid} from "nanoid";
const jdidKey = 'jdid'

interface Config {
apiKey: string;
env: string
apiKey: string;
env: string
}

export class FakeSdk {
private config: Config
private jdid: string;

constructor(config: Config, request?: Request) {
const isSsr = typeof window === 'undefined'
console.log(typeof window)

let jdid: string;
if (isSsr) {
if (!request) {
throw new Error('When the SDK is used in an SSR context, a HTTP request must be included for initialization')
}
jdid = this.readJdidCookie(request) ?? this.generateJdid()
} else {
if (request) {
throw new Error("Don't include a HTTP request for CSR usage")
}
jdid = this.getLocalStorageJdid()
}

this.jdid = jdid;
this.config = config
}

makeJdidCookie(): string {
return `${jdidKey}=${this.jdid};`
private config: Config
private jdid: string;

constructor(config: Config, request?: Request) {
const isSsr = typeof window === 'undefined'

let jdid: string;
if (isSsr) {
if (!request) {
throw new Error('When the SDK is used in an SSR context, an HTTP request must be included for initialization')
}
jdid = this.readJdidCookie(request) ?? this.generateJdid()
} else {
if (request) {
throw new Error("Don't include a HTTP request for CSR usage")
}
jdid = this.getLocalStorageJdid()
}

fetchAd(type: string): Ad {
const flight = nanoid()
return new Ad({type, flight})
}
this.jdid = jdid;
this.config = config
}

private getLocalStorageJdid() {
let jdid = this.readLocalStorage()
if (!jdid) {
jdid = this.generateJdid()
this.setLocalStorage(jdid)
}
return jdid
}
makeJdidCookie(): string {
return `${jdidKey}=${this.jdid};`
}

private readLocalStorage() {
return localStorage.getItem(jdidKey)
}
fetchAd(type: string): Ad {
const flight = nanoid()
return new Ad({type, flight})
}

private setLocalStorage(jdid: string) {
localStorage.setItem(jdidKey, jdid)
private getLocalStorageJdid() {
let jdid = this.readLocalStorage()
if (!jdid) {
jdid = this.generateJdid()
this.setLocalStorage(jdid)
}

private readJdidCookie(request: Request): string | undefined {
const cookieHeader = request.headers.get('cookie')
let jdid: string | undefined = undefined;
if (cookieHeader) {
cookieHeader.split(';').find((cookie) => {
const parts = cookie.split('=')
if (parts[0] === jdidKey) {
jdid = parts[1]
console.log('sdk:'+jdid)
}
})
return jdid
}

private readLocalStorage() {
return localStorage.getItem(jdidKey)
}

private setLocalStorage(jdid: string) {
localStorage.setItem(jdidKey, jdid)
}

private readJdidCookie(request: Request): string | undefined {
const cookieHeader = request.headers.get('cookie')
let jdid: string | undefined = undefined;
if (cookieHeader) {
cookieHeader.split(';').find((cookie) => {
const parts = cookie.split('=')
if (parts[0] === jdidKey) {
jdid = parts[1]
}
return jdid
})
}
return jdid
}

private generateJdid() {
return nanoid()
}
private generateJdid() {
return nanoid()
}

}

interface AdProps {
type: string;
flight: string;
type: string;
flight: string;
}

export class Ad {
readonly type: string;
readonly flight: string;
readonly type: string;
readonly flight: string;

constructor({type, flight}: AdProps) {
this.type = type;
this.flight = flight;
}
constructor({type, flight}: AdProps) {
this.type = type;
this.flight = flight;
}

serialize(): AdProps {
return {
type: this.type,
flight: this.flight,
}
serialize(): AdProps {
return {
type: this.type, flight: this.flight,
}
}

click(productId: number) {
console.log('tracking click')
this.logData(productId)
}
click(productId: number) {
console.log('tracking click')
this.logData(productId)
}

impress(productId: number) {
console.log('tracking impression')
this.logData(productId)
}
impress(productId: number) {
console.log('tracking impression')
this.logData(productId)
}

private logData (productId: number) {
console.log({productId, type: this.type, flight: this.flight})
}
private logData(productId: number) {
console.log({productId, type: this.type, flight: this.flight})
}


}

0 comments on commit d52ac90

Please sign in to comment.