@wavebirdai/api 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +55 -2
- package/bin/wavebird-next.mjs +67 -0
- package/dist/browser.d.ts +27 -0
- package/dist/browser.js +194 -0
- package/dist/generation.js +96 -0
- package/dist/server.d.ts +38 -0
- package/dist/server.js +349 -0
- package/examples/next-js/.env.example +6 -0
- package/examples/next-js/app/api/generate/route.js +6 -0
- package/examples/next-js/app/api/sponsor-consent/route.js +4 -0
- package/examples/next-js/app/api/sponsor-slot/route.js +3 -0
- package/examples/next-js/app/layout.jsx +3 -0
- package/examples/next-js/app/page.jsx +59 -0
- package/examples/next-js/lib/auth.js +12 -0
- package/examples/next-js/lib/model.js +3 -0
- package/examples/next-js/lib/publisher.js +30 -0
- package/examples/next-js/package.json +7 -0
- package/examples/next-ts/.env.example +6 -0
- package/examples/next-ts/app/api/generate/route.ts +6 -0
- package/examples/next-ts/app/api/sponsor-consent/route.ts +4 -0
- package/examples/next-ts/app/api/sponsor-slot/route.ts +3 -0
- package/examples/next-ts/app/layout.tsx +5 -0
- package/examples/next-ts/app/page.tsx +60 -0
- package/examples/next-ts/lib/auth.ts +12 -0
- package/examples/next-ts/lib/model.ts +3 -0
- package/examples/next-ts/lib/publisher.ts +30 -0
- package/examples/next-ts/package.json +8 -0
- package/examples/next-ts/tsconfig.json +20 -0
- package/package.json +21 -4
- package/templates/NEXT-SETUP.md +11 -0
- package/templates/WavebirdPlacement.jsx +31 -0
- package/templates/WavebirdPlacement.tsx +36 -0
- package/templates/model.js +3 -0
- package/templates/model.ts +3 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wavebird-api-next-ts-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": { "dev": "next dev", "build": "next build --webpack", "typecheck": "tsc --noEmit" },
|
|
6
|
+
"dependencies": { "next": "16.3.8", "react": "19.2.4", "react-dom": "19.2.4" },
|
|
7
|
+
"devDependencies": { "@types/node": "^25", "@types/react": "^19", "@types/react-dom": "^19", "typescript": "^5" }
|
|
8
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "es2022"],
|
|
5
|
+
"allowJs": false,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [{ "name": "next" }]
|
|
17
|
+
},
|
|
18
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
19
|
+
"exclude": ["node_modules"]
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wavebirdai/api",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Banner/Native publisher integration for the wavebird API",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": { "type": "git", "url": "https://github.com/wavebird-ai/api" },
|
|
9
|
+
"engines": { "node": ">=20" },
|
|
10
|
+
"files": ["dist", "examples", "bin", "templates", "README.md", "LICENSE"],
|
|
11
|
+
"bin": { "wavebird-next": "./bin/wavebird-next.mjs" },
|
|
12
|
+
"exports": {
|
|
13
|
+
"./server": { "types": "./dist/server.d.ts", "import": "./dist/server.js" },
|
|
14
|
+
"./browser": { "types": "./dist/browser.d.ts", "import": "./dist/browser.js" },
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "node build.mjs",
|
|
19
|
+
"test": "node --test tests/*.test.mjs",
|
|
20
|
+
"pretest": "npm run build",
|
|
21
|
+
"prepack": "npm run build"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Connect wavebird to this Next.js app
|
|
2
|
+
|
|
3
|
+
The generator installed `lib/publisher`, `lib/auth`, and `lib/model`; `app/api/generate`, `app/api/sponsor-slot`, and `app/api/sponsor-consent`; and `components/WavebirdPlacement` (under `src/` when `src/app` was selected). No existing page was replaced.
|
|
4
|
+
|
|
5
|
+
1. Set server-only `WAVEBIRD_CLIENT_ID`, `WAVEBIRD_SECRET_KEY`, `WAVEBIRD_PREFERENCE_SECRET`, and `WAVEBIRD_PUBLIC_ORIGINS`. The last value is a comma-separated list of the exact scheme, host, and port where your app is opened. Keep the Dashboard project domain at your real HTTPS host. For local Server Test-key testing, include the exact loopback origin in `WAVEBIRD_PUBLIC_ORIGINS` without changing that project domain; Browser Test Keys instead use their separate Allowed origins field in API Keys. `localhost` and `127.0.0.1` are distinct. Do not use wildcards. The package rejects an absent or malformed list. Never expose the key or preference secret through `NEXT_PUBLIC_` or client props. `clientId` is the public project ID.
|
|
6
|
+
2. Replace `lib/publisher`'s example surface, placement, dimensions, formats, locale, consent mode, and publisher identity with the **saved Dashboard values**. The responsive example lists 728×90 and 320×50 Banner sizes only to show the size-selection shape. Keep `responsiveSizeSelection: true` only when the selected project and placement approve every configured size. Remove any size absent from the saved project before Test traffic. The API enforces its own authority; example values do not create a valid placement.
|
|
7
|
+
3. Connect `lib/auth` to the app's real session authorization. Its supplied path check fails closed when `PUBLISHER_AUTH_CHECK_PATH` is absent. The path must be a publisher-owned same-origin route that returns 204 only for an authorized user; it must not be any wavebird route.
|
|
8
|
+
4. Connect `lib/model` to the existing generation stream. The installed function throws until replaced. Keep the existing generation response and pass the supplied abort signal to it. Do not put model calls in the browser solely for this integration.
|
|
9
|
+
5. In an existing client page, mount `<WavebirdPlacement clientId={publicProjectId} userId={authenticatedUserId} conversationId={activeConversationId} onReady={setAds} />` beside the real generation result, outside the input and transcript. When the user starts their existing generation, call `ads.connectGeneration({ signal, request: headers => fetch('/api/generate', { method: 'POST', headers, signal }), consume: async (response, lifecycle) => { /* consume your existing stream and call lifecycle.onDelta() for each delta */ } })`. Abort that same signal on Stop or unmount. Use a stable `onReady` callback. This example uses wavebird's consent dialog; if the saved project uses the publisher's own CMP, connect its real grant/deny/withdrawal/expiry/GPC lifecycle instead of changing only the label.
|
|
10
|
+
|
|
11
|
+
These routes are real required Next.js files, not hidden package behavior. The package has no knowledge of your login session, CMP, or model stream. Start with a Test project and check that No-Fill, abort and late responses never block the primary result; all Test facts must remain nonpayable.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { createPublisherAds } from "@wavebirdai/api/browser";
|
|
5
|
+
|
|
6
|
+
export function WavebirdPlacement({ clientId, userId, conversationId, onReady }) {
|
|
7
|
+
const target = useRef(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!target.current || !clientId || !userId || !conversationId) return;
|
|
10
|
+
const ads = createPublisherAds({
|
|
11
|
+
target: target.current,
|
|
12
|
+
clientId,
|
|
13
|
+
surfaceId: "chat_assistant",
|
|
14
|
+
jobType: "chat",
|
|
15
|
+
timing: "during",
|
|
16
|
+
consentMode: "wavebird_consent",
|
|
17
|
+
userId,
|
|
18
|
+
conversationId,
|
|
19
|
+
rendererUrl: "https://api.wavebird.ai/v1/render.js",
|
|
20
|
+
placementEndpoint: "/api/sponsor-slot",
|
|
21
|
+
consentEndpoint: "/api/sponsor-consent",
|
|
22
|
+
privacySettingsTarget: "#wavebird-privacy-settings"
|
|
23
|
+
});
|
|
24
|
+
onReady?.(ads);
|
|
25
|
+
return () => { onReady?.(null); ads.dispose(); };
|
|
26
|
+
}, [clientId, userId, conversationId, onReady]);
|
|
27
|
+
return <>
|
|
28
|
+
<button id="wavebird-privacy-settings" type="button">Sponsored choices</button>
|
|
29
|
+
<section ref={target} aria-label="Sponsored placement area" style={{ width: "100%", maxWidth: 728, height: 346 }} />
|
|
30
|
+
</>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { createPublisherAds, type PublisherAds } from "@wavebirdai/api/browser";
|
|
5
|
+
|
|
6
|
+
export function WavebirdPlacement({ clientId, userId, conversationId, onReady }: {
|
|
7
|
+
clientId: string;
|
|
8
|
+
userId: string;
|
|
9
|
+
conversationId: string;
|
|
10
|
+
onReady?: (ads: PublisherAds | null) => void;
|
|
11
|
+
}) {
|
|
12
|
+
const target = useRef<HTMLElement | null>(null);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (!target.current || !clientId || !userId || !conversationId) return;
|
|
15
|
+
const ads = createPublisherAds({
|
|
16
|
+
target: target.current,
|
|
17
|
+
clientId,
|
|
18
|
+
surfaceId: "chat_assistant",
|
|
19
|
+
jobType: "chat",
|
|
20
|
+
timing: "during",
|
|
21
|
+
consentMode: "wavebird_consent",
|
|
22
|
+
userId,
|
|
23
|
+
conversationId,
|
|
24
|
+
rendererUrl: "https://api.wavebird.ai/v1/render.js",
|
|
25
|
+
placementEndpoint: "/api/sponsor-slot",
|
|
26
|
+
consentEndpoint: "/api/sponsor-consent",
|
|
27
|
+
privacySettingsTarget: "#wavebird-privacy-settings"
|
|
28
|
+
});
|
|
29
|
+
onReady?.(ads);
|
|
30
|
+
return () => { onReady?.(null); ads.dispose(); };
|
|
31
|
+
}, [clientId, userId, conversationId, onReady]);
|
|
32
|
+
return <>
|
|
33
|
+
<button id="wavebird-privacy-settings" type="button">Sponsored choices</button>
|
|
34
|
+
<section ref={target} aria-label="Sponsored placement area" style={{ width: "100%", maxWidth: 728, height: 346 }} />
|
|
35
|
+
</>;
|
|
36
|
+
}
|