Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,34 @@ jobs:
headers: |
x-goog-meta-optable-sdk-version: ${{ github.ref_name }}

deploy-pub-template-to-gcs:
needs: [deploy-sdk-to-npm, define-gcs-versions-to-update]
strategy:
matrix:
sdk-version: ${{ fromJSON(needs.define-gcs-versions-to-update.outputs.sdk-versions) }}
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Auth to google cloud
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ env.workload_identity_provider }}
service_account: ${{ env.service-account }}

- name: Upload pub.ts template to GCS bucket
uses: google-github-actions/upload-cloud-storage@v2
with:
path: "browser/pub.ts"
destination: "optable-web-sdk/pub-sdk/${{ matrix.sdk-version }}"
process_gcloudignore: false
headers: |
x-goog-meta-optable-sdk-version: ${{ github.ref_name }}

deploy-demo:
needs: [deploy-sdk-to-npm]
permissions:
Expand Down Expand Up @@ -181,7 +209,16 @@ jobs:
run: docker push us-docker.pkg.dev/optable-artifact-registry/optable/optable-web-sdk-demos:${{ github.ref_name }}

slack-notification:
needs: [tests-prettier, build, deploy-sdk-to-npm, define-gcs-versions-to-update, deploy-sdk-to-gcs, deploy-demo]
needs:
[
tests-prettier,
build,
deploy-sdk-to-npm,
define-gcs-versions-to-update,
deploy-sdk-to-gcs,
deploy-pub-template-to-gcs,
deploy-demo,
]
runs-on: ubuntu-22.04
if: ${{ failure() }}
steps:
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/reusable-lint-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@ jobs:
- name: Test
run: pnpm test

validate-pub-template:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check if pub template files changed
id: changed
run: |
if git diff --name-only origin/master...HEAD | grep -qE '^(browser/pub\.ts|scripts/validate-pub-template\.sh)$'; then
echo "pub_changed=true" >> "$GITHUB_OUTPUT"
else
echo "pub_changed=false" >> "$GITHUB_OUTPUT"
fi

- name: Validate pub.ts template
if: steps.changed.outputs.pub_changed == 'true'
run: ./scripts/validate-pub-template.sh

prettier:
runs-on: ubuntu-22.04
steps:
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

# build outputs
browser/dist

# Go text/template file (not valid TypeScript)
browser/pub.ts
lib/dist

# demos
Expand Down
150 changes: 150 additions & 0 deletions browser/pub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// browser/pub.ts — Go text/template + TypeScript
// This file is processed by Go text/template BEFORE esbuild compilation.
// It is NOT valid TypeScript until template directives are resolved.
//
// Template variables:
// .Host - Edge API hostname (e.g. "ca.edge.optable.co")
// .Site - Site slug derived from origin
// .Node - Node slug derived from tenant
// .Timeout - Optional timeout hint (e.g. "500ms", "2s")
// .PrebidGlobal - Prebid.js global variable name (e.g. "pbjs", "__pmc_atlasmg_pbjs")
// .TcfeuVendorID - Optional TCF EU vendor ID (GVLID) for consent checks
// .TcfcaVendorID - Optional TCF CA vendor ID (GVLID) for consent checks
// .EnableSecureSignals - Boolean: enable GPT Secure Signals
// .EnableBotDetection - Boolean: enable bot detection
// .EnableAnalytics - Boolean: enable Prebid analytics
// .GeoTargeting - "regional" or "multi-region"

import OptableSDK from "@optable/web-sdk";
{{if .EnableAnalytics}}
import OptablePrebidAnalytics from "@optable/web-sdk/lib/dist/addons/prebid/analytics";
{{end}}

declare global {
interface Window {
optable?: Record<string, any>;
}
}

// --- Commands queue (executes queued functions immediately) ---
class OptableCommands {
constructor(cmds: OptableCommands | Function[]) {
if (Array.isArray(cmds)) {
for (const cmd of cmds) {
if (typeof cmd === "function") cmd();
}
}
}
push(cmd: Function) {
cmd();
}
}

// --- Debug logging ---
function optableMessage(...args: unknown[]) {
if (sessionStorage.optableDebug) {
console.log("[OPTABLE WRAPPER]", ...args);
}
}

// --- URL query feature flags ---
function setOptableFlagsFromURLQuery() {
const keys = ["optableDebug", "optableDisableConsent", "optableResolveTD", "optableEnableAnalytics"];
const search = window.location.search || "";
keys.forEach((key) => {
if (search.match(new RegExp(key, "g"))) {
sessionStorage.setItem(key, "1");
}
});
}

// --- Consent handling ---
function getConsent() {
if (sessionStorage.optableDisableConsent) {
return {
createProfilesForAdvertising: true,
deviceAccess: true,
measureAdvertisingPerformance: true,
reg: null,
useProfilesForAdvertising: true,
};
}
return { cmpapi: {
{{- if .TcfeuVendorID}}
tcfeuVendorID: {{.TcfeuVendorID}},
{{- end}}
{{- if .TcfcaVendorID}}
tcfcaVendorID: {{.TcfcaVendorID}},
{{- end}}
} };
}

{{if .EnableAnalytics}}
// --- Analytics initialization ---
function initPrebidAnalytics(sdk: OptableSDK) {
const pbjsObject = (window as any)["{{.PrebidGlobal}}"] || (window as any)["pbjs"];
if (!pbjsObject) return;

const analyticsSDK = new OptableSDK({
host: "{{.Host}}",
node: "analytics",
site: "analytics",
readOnly: true,
cookies: false,
});

const analytics = new OptablePrebidAnalytics(analyticsSDK, {
analytics: true,
tenant: "{{.Node}}",
debug: !!sessionStorage.optableDebug,
samplingRate: 0.1,
});

analytics.hookIntoPrebid(pbjsObject);
}
{{end}}

// --- Main execution ---
(function run() {
setOptableFlagsFromURLQuery();

window.optable = window.optable || {};
window.optable.SDK = OptableSDK;

const consent = getConsent();
const sdk = new OptableSDK({
host: "{{.Host}}",
site: "{{.Site}}",
node: "{{.Node}}",
cookies: false,
consent,
initPassport: false,
{{- if .Timeout}}
timeout: "{{.Timeout}}",
{{- end}}
});

window.optable["{{.Node}}_instance"] = sdk;

{{if .EnableSecureSignals}}
optableMessage("Enabling secure signals");
sdk.installGPTSecureSignals();
{{end}}

{{if .EnableBotDetection}}
optableMessage("Enabling bot detection");
(sdk as any).enableBotDetection();
{{end}}

{{if eq .GeoTargeting "multi-region"}}
optableMessage("Multi-region mode: reading window.optable.countryCode");
(sdk as any).setCountryCodeFromGlobal();
{{end}}

{{if .EnableAnalytics}}
initPrebidAnalytics(sdk);
{{end}}

window.optable.cmd = new OptableCommands(window.optable.cmd || []);
optableMessage("SDK initialized");
})();
50 changes: 50 additions & 0 deletions scripts/validate-pub-template.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Validates that browser/pub.ts renders to compilable TypeScript.
#
# This script simulates Go text/template rendering by replacing template
# directives with sample values, then compiles the result with esbuild
# to catch syntax errors before they reach a release.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
TEMPLATE="${REPO_ROOT}/browser/pub.ts"
WORKDIR="$(mktemp -d)"

trap 'rm -rf "${WORKDIR}"' EXIT

echo "Validating pub.ts template..."

# Render template with sample config values.
# Features that depend on SDK methods not yet implemented are disabled.
rendered="${WORKDIR}/pub.ts"

sed \
-e '/{{if/d' \
-e '/{{end}}/d' \
-e 's/{{- if [^}]*}}//' \
-e 's/{{- end}}//' \
-e 's/{{\.Host}}/sample.edge.example.co/g' \
-e 's/{{\.Site}}/sample-site/g' \
-e 's/{{\.Node}}/sample-node/g' \
-e 's/{{\.PrebidGlobal}}/pbjs/g' \
-e 's/{{\.Timeout}}/500ms/g' \
-e 's/{{\.TcfeuVendorID}}/123/g' \
-e 's/{{\.TcfcaVendorID}}/456/g' \
"${TEMPLATE}" > "${rendered}"

echo "Rendered template to ${rendered}"

# Compile with esbuild to verify the output is valid TypeScript.
# @optable/web-sdk is marked external since it's resolved at bundle time (Phase 5).
npx --yes esbuild "${rendered}" \
--bundle \
--format=iife \
--platform=browser \
--target=es2015 \
--external:@optable/web-sdk \
--external:@optable/web-sdk/* \
--outfile="${WORKDIR}/pub.js"

echo "Template validation passed: pub.ts renders to compilable TypeScript."
Loading