first commit
Some checks failed
Release / Release (push) Failing after 1m44s

This commit is contained in:
Lectom C Han
2025-07-07 18:53:25 +09:00
commit 421105f082
102 changed files with 63663 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {},
};
module.exports = nextConfig;

View File

@@ -0,0 +1,21 @@
{
"name": "next-with-approuter",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 4000",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "20.5.7",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"next": "13.4.19",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "5.2.2",
"@aptabase/react": "*"
}
}

View File

@@ -0,0 +1,27 @@
'use client';
import { useAptabase } from '@aptabase/react';
import { useState } from 'react';
export function Counter() {
const { trackEvent } = useAptabase();
const [count, setCount] = useState(0);
function increment() {
setCount((c) => c + 1);
trackEvent('increment');
}
function decrement() {
setCount((c) => c - 1);
trackEvent('decrement');
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

View File

@@ -0,0 +1,11 @@
import { AptabaseProvider } from '@aptabase/react';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<AptabaseProvider appKey="A-US-5431775171">{children}</AptabaseProvider>
</body>
</html>
);
}

View File

@@ -0,0 +1,9 @@
import { Counter } from './Counter';
export default async function Home() {
return (
<main>
Aptabase + Next.js App Router <br /> <Counter />
</main>
);
}

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
experimental: {},
};
module.exports = nextConfig;

View File

@@ -0,0 +1,21 @@
{
"name": "next-with-pages",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev -p 4000",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "20.5.7",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"next": "13.4.19",
"react": "18.2.0",
"react-dom": "18.2.0",
"typescript": "5.2.2",
"@aptabase/react": "*"
}
}

View File

@@ -0,0 +1,25 @@
import { useAptabase } from '@aptabase/react';
import { useState } from 'react';
export function Counter() {
const { trackEvent } = useAptabase();
const [count, setCount] = useState(0);
function increment() {
setCount((c) => c + 1);
trackEvent('increment');
}
function decrement() {
setCount((c) => c - 1);
trackEvent('decrement');
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

View File

@@ -0,0 +1,10 @@
import { AptabaseProvider } from '@aptabase/react';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<AptabaseProvider appKey="A-DEV-0000000000">
<Component {...pageProps} />
</AptabaseProvider>
);
}

View File

@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}

View File

@@ -0,0 +1,9 @@
import type { NextApiRequest, NextApiResponse } from 'next';
type Data = {
name: string;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse<Data>) {
res.status(200).json({ name: 'John Doe' });
}

View File

@@ -0,0 +1,23 @@
import { Counter } from '@/components/Counter';
import { GetServerSideProps } from 'next';
import Head from 'next/head';
export const getServerSideProps: GetServerSideProps = async ({ req }) => {
return { props: {} };
};
export default function Home() {
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<main>
Aptabase + Next.js Pages Router <br />
<Counter />
</main>
</>
);
}

View File

@@ -0,0 +1,35 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": [
"./src/*"
]
},
"forceConsistentCasingInFileNames": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -0,0 +1,5 @@
import { init, trackEvent } from '@aptabase/browser';
init('A-DEV-0000000000');
trackEvent('background_service_started');

View File

@@ -0,0 +1,33 @@
{
"name": "plasmo-browserext",
"private": true,
"displayName": "Plasmo browserext",
"version": "0.0.1",
"description": "A basic Plasmo extension.",
"author": "Plasmo Corp. <foss@plasmo.com>",
"scripts": {
"dev": "plasmo dev",
"build": "plasmo build",
"test": "plasmo test"
},
"dependencies": {
"plasmo": "0.84.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"@aptabase/browser": "*"
},
"devDependencies": {
"@types/chrome": "0.0.254",
"@types/react": "18.2.45",
"@types/react-dom": "18.2.17",
"typescript": "5.3.3"
},
"manifest": {
"permissions": [
"storage"
],
"host_permissions": [
"https://*/*"
]
}
}

View File

@@ -0,0 +1,25 @@
import { trackEvent } from '@aptabase/browser';
import { useState } from 'react';
function IndexPopup() {
const [count, setCount] = useState(0);
function increment() {
trackEvent('increment', { count: count + 1 });
setCount((c) => c + 1);
}
function decrement() {
trackEvent('decrement', { count: count - 1 });
setCount((c) => c - 1);
}
return (
<div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>decrement</button>
</div>
);
}
export default IndexPopup;

View File

@@ -0,0 +1,11 @@
{
"extends": "plasmo/templates/tsconfig.base",
"exclude": ["node_modules"],
"include": [".plasmo/index.d.ts", "./**/*.ts", "./**/*.tsx"],
"compilerOptions": {
"paths": {
"~*": ["./*"]
},
"baseUrl": "."
}
}

View File

@@ -0,0 +1,25 @@
import { useAptabase } from '@aptabase/react';
import { useState } from 'react';
export function Counter() {
const { trackEvent } = useAptabase();
const [count, setCount] = useState(0);
function increment() {
setCount((c) => c + 1);
trackEvent('increment');
}
function decrement() {
setCount((c) => c - 1);
trackEvent('decrement');
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
}

View File

@@ -0,0 +1,21 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/
import { AptabaseProvider } from '@aptabase/react';
import { RemixBrowser } from '@remix-run/react';
import { startTransition, StrictMode } from 'react';
import { hydrateRoot } from 'react-dom/client';
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<AptabaseProvider appKey="A-DEV-0000000000">
<RemixBrowser />
</AptabaseProvider>
</StrictMode>,
);
});

View File

@@ -0,0 +1,135 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/
import { PassThrough } from "node:stream";
import type { AppLoadContext, EntryContext } from "@remix-run/node";
import { Response } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import isbot from "isbot";
import { renderToPipeableStream } from "react-dom/server";
const ABORT_DELAY = 5_000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
loadContext: AppLoadContext
) {
return isbot(request.headers.get("user-agent"))
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
);
}
function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onAllReady() {
shellRendered = true;
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
})
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);
setTimeout(abort, ABORT_DELAY);
});
}
function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onShellReady() {
shellRendered = true;
const body = new PassThrough();
responseHeaders.set("Content-Type", "text/html");
resolve(
new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
})
);
pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);
setTimeout(abort, ABORT_DELAY);
});
}

View File

@@ -0,0 +1,33 @@
import { cssBundleHref } from "@remix-run/css-bundle";
import type { LinksFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
export const links: LinksFunction = () => [
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
];
export default function App() {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -0,0 +1,9 @@
import { Counter } from '~/components/Counter';
export default function Index() {
return (
<main>
Aptabase + Remix <br /> <Counter />
</main>
);
}

View File

@@ -0,0 +1,30 @@
{
"name": "remix-example",
"private": true,
"sideEffects": false,
"scripts": {
"build": "remix build",
"dev": "PORT=4000 remix dev",
"start": "remix-serve build",
"typecheck": "tsc"
},
"dependencies": {
"@remix-run/css-bundle": "1.19.3",
"@remix-run/node": "1.19.3",
"@remix-run/react": "1.19.3",
"@remix-run/serve": "1.19.3",
"isbot": "3.6.8",
"react": "18.2.0",
"react-dom": "18.2.0",
"@aptabase/react": "*"
},
"devDependencies": {
"@remix-run/dev": "1.19.3",
"@remix-run/eslint-config": "1.19.3",
"@types/react": "18.0.35",
"@types/react-dom": "18.0.11"
},
"engines": {
"node": ">=14.0.0"
}
}

View File

@@ -0,0 +1,17 @@
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
serverModuleFormat: "cjs",
future: {
v2_dev: true,
v2_errorBoundary: true,
v2_headers: true,
v2_meta: true,
v2_normalizeFormMethod: true,
v2_routeConvention: true,
},
};

2
examples/remix-app/remix.env.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node" />

View File

@@ -0,0 +1,22 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -0,0 +1,90 @@
# 정적 JS 파일 빌드 및 문제 해결 가이드
이 문서는 `aptabase.min.js``aptabase.debug.js` 파일을 빌드하고, 빌드 과정에서 발생한 문제들을 해결하는 과정을 기록합니다.
## 초기화 및 이벤트 전송
### 기본 사용법
`trackEvent` 함수를 사용하여 이벤트를 전송할 때, 두 번째 인자로 JavaScript 객체를 전달하여 사용자 정의 속성(`props`)을 함께 보낼 수 있습니다. `props` 객체의 값으로는 문자열, 숫자, 불리언 타입이 가능합니다.
**예제:**
```html
<script>
// Aptabase 초기화
window.aptabase.init("YOUR_APP_KEY");
function track(eventName, props) {
// 이벤트와 함께 props 전송
window.aptabase.trackEvent(eventName, props);
console.log(`Event '${eventName}' sent!`, props ? { props } : '');
}
</script>
<!-- props 없이 이벤트 전송 -->
<button onclick="track('app_started')">Track: App Started</button>
<!-- props와 함께 이벤트 전송 -->
<button onclick="track('feature_a_used', { plan: 'premium', from: 'sidebar' })">Track: Used Feature A</button>
<button onclick="track('item_purchased', { item_id: 'SKU-123', price: 9.99, on_sale: true })">Track: Item Purchased</button>
```
### Self-Hosted 환경 초기화
자체 호스팅(Self-hosting) 환경의 Aptabase를 사용하는 경우, `init` 함수의 두 번째 인자로 `host` 옵션을 반드시 전달해야 합니다. Self-hosted용 App Key는 일반적으로 `SH` 지역 코드를 포함합니다.
**예제:**
```html
<script>
// Self-Hosted용 App Key와 host 주소를 사용하여 초기화
window.aptabase.init("A-SH-YOUR_UNIQUE_ID", {
host: "https://your-aptabase-instance.com"
});
function track(eventName, props) {
window.aptabase.trackEvent(eventName, props);
console.log(`Event '${eventName}' sent!`);
}
</script>
```
---
## 빌드 문제 해결 과정
### 1. `tsup` 빌드 설정 수정
- **문제**: 초기 `tsup.config.ts` 설정은 `aptabase.min.js``aptabase.debug.js`를 명시적으로 생성하지 않아 minify 과정에서 문제가 발생할 가능성이 있었습니다.
- **해결**: `tsup.config.ts` 파일을 수정하여 디버그와 minify 버전을 각각 다른 `define` 설정을 통해 생성하도록 빌드 구성을 분리했습니다.
### 2. `pnpm` 워크스페이스 설정
- **문제**: `pnpm`을 사용하는 모노레포 환경에서 `pnpm install`을 실행했음에도 `tsup` 명령어를 찾지 못하는 문제가 발생했습니다.
- **원인**: `pnpm-workspace.yaml` 파일이 없어 `pnpm`이 워크스페이스를 올바르게 인식하지 못했습니다.
- **해결**: 프로젝트 루트에 `pnpm-workspace.yaml` 파일을 생성하고 `packages``examples` 디렉토리를 워크스페이스로 지정한 후, `pnpm install`을 다시 실행하여 의존성을 올바르게 설치했습니다.
### 3. 타입 정의(Typings) 문제 해결
- **문제**: 빌드 중 `Cannot find name 'chrome'``Cannot find name 'process'`와 같은 타입스크립트 컴파일 오류가 발생했습니다.
- **원인**: 브라우저 및 Node.js 환경에서만 제공되는 전역 객체(`chrome`, `process`)에 대한 타입 정의가 없었습니다.
- **해결**:
1. `@types/chrome``@types/node` 패키지를 개발 의존성으로 설치했습니다.
2. `packages/web/tsconfig.json``compilerOptions.types` 배열에 `"chrome"``"node"`를 추가하여 타입스크립트가 해당 타입들을 인식하도록 설정했습니다.
### 4. `process` is not defined` 런타임 오류 해결
- **문제**: 빌드된 `aptabase.min.js` 파일을 브라우저에서 실행할 때 `ReferenceError: process is not defined` 런타임 오류가 발생했습니다.
- **원인**: 소스코드(`shared.ts`, `index.ts`)에서 `process.env.NODE_ENV``process.env.PKG_VERSION`을 참조하고 있었고, 이 코드가 브라우저 환경에서 실행<EC8BA4><ED9689>면서 `process` 객체를 찾지 못해 오류가 발생했습니다.
- **해결**: `tsup.config.ts``define` 옵션을 사용하여 빌드 시점에 해당 환경 변수들을 실제 값으로 교체하도록 설정했습니다.
- `aptabase.min.js` (프로덕션용): `process.env.NODE_ENV``'production'`으로 설정
- `aptabase.debug.js` (디버그용): `process.env.NODE_ENV``'development'`로 설정
## 최종 빌드 방법
위의 모든 문제 해결 후, 다음 명령어를 사용하여 성공적으로 `aptabase.min.js``aptabase.debug.js` 파일을 빌드할 수 있습니다.
```bash
# 프로젝트 루트 디렉토리에서 실행
pnpm --filter @aptabase/web build
```

View File

@@ -0,0 +1,175 @@
"use strict";
var aptabase = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
init: () => init,
trackEvent: () => trackEvent
});
// ../shared.ts
var defaultLocale;
var defaultIsDebug;
var isInBrowser = typeof window !== "undefined" && typeof window.fetch !== "undefined";
var isInBrowserExtension = typeof chrome !== "undefined" && !!chrome.runtime?.id;
var _sessionId = newSessionId();
var _lastTouched = /* @__PURE__ */ new Date();
var _hosts = {
US: "https://us.aptabase.com",
EU: "https://eu.aptabase.com",
DEV: "https://localhost:3000",
SH: ""
};
function inMemorySessionId(timeout) {
let now = /* @__PURE__ */ new Date();
const diffInMs = now.getTime() - _lastTouched.getTime();
const diffInSec = Math.floor(diffInMs / 1e3);
if (diffInSec > timeout) {
_sessionId = newSessionId();
}
_lastTouched = now;
return _sessionId;
}
function newSessionId() {
const epochInSeconds = Math.floor(Date.now() / 1e3).toString();
const random = Math.floor(Math.random() * 1e8).toString().padStart(8, "0");
return epochInSeconds + random;
}
function validateAppKey(appKey) {
const parts = appKey.split("-");
if (parts.length !== 3 || _hosts[parts[1]] === void 0) {
console.warn(`The Aptabase App Key "${appKey}" is invalid. Tracking will be disabled.`);
return false;
}
return true;
}
function getApiUrl(appKey, options) {
const region = appKey.split("-")[1];
if (region === "SH") {
if (!options?.host) {
console.warn(`Host parameter must be defined when using Self-Hosted App Key. Tracking will be disabled.`);
return;
}
return `${options.host}/api/v0/event`;
}
const host = options?.host ?? _hosts[region];
return `${host}/api/v0/event`;
}
async function sendEvent(opts) {
if (!isInBrowser && !isInBrowserExtension) {
console.warn(`Aptabase: trackEvent requires a browser environment. Event "${opts.eventName}" will be discarded.`);
return;
}
if (!opts.appKey) {
console.warn(`Aptabase: init must be called before trackEvent. Event "${opts.eventName}" will be discarded.`);
return;
}
try {
const response = await fetch(opts.apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"App-Key": opts.appKey
},
credentials: "omit",
body: JSON.stringify({
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
sessionId: opts.sessionId,
eventName: opts.eventName,
systemProps: {
locale: opts.locale ?? getBrowserLocale(),
isDebug: opts.isDebug ?? getIsDebug(),
appVersion: opts.appVersion ?? "",
sdkVersion: opts.sdkVersion
},
props: opts.props
})
});
if (response.status >= 300) {
const responseBody = await response.text();
console.warn(`Failed to send event "${opts.eventName}": ${response.status} ${responseBody}`);
}
} catch (e) {
console.warn(`Failed to send event "${opts.eventName}"`);
console.warn(e);
}
}
function getBrowserLocale() {
if (defaultLocale) {
return defaultLocale;
}
if (typeof navigator === "undefined") {
return void 0;
}
if (navigator.languages.length > 0) {
defaultLocale = navigator.languages[0];
} else {
defaultLocale = navigator.language;
}
return defaultLocale;
}
function getIsDebug() {
if (defaultIsDebug !== void 0) {
return defaultIsDebug;
}
if (true) {
defaultIsDebug = true;
return defaultIsDebug;
}
if (typeof location === "undefined") {
defaultIsDebug = false;
return defaultIsDebug;
}
defaultIsDebug = location.hostname === "localhost";
return defaultIsDebug;
}
// src/index.ts
var SESSION_TIMEOUT = 1 * 60 * 60;
var sdkVersion = `aptabase-web@${"0.4.3"}`;
var _appKey = "";
var _apiUrl;
var _options;
function init(appKey, options) {
if (!validateAppKey(appKey))
return;
_apiUrl = options?.apiUrl ?? getApiUrl(appKey, options);
_appKey = appKey;
_options = options;
}
async function trackEvent(eventName, props) {
if (!_apiUrl)
return;
const sessionId = inMemorySessionId(SESSION_TIMEOUT);
await sendEvent({
apiUrl: _apiUrl,
sessionId,
appKey: _appKey,
isDebug: _options?.isDebug,
appVersion: _options?.appVersion,
sdkVersion,
eventName,
props
});
}
return __toCommonJS(src_exports);
})();
//# sourceMappingURL=aptabase.debug.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Aptabase Standalone Example</title>
<!-- <script src="https://static.hmac.kr/aptabase.min.js"></script> -->
<!-- <script src="./packages/web/dist/aptabase.min.js"></script> -->
<script src="./aptabase.min.js"></script>
<style>
body { font-family: sans-serif; padding: 2em; }
button { display: block; margin-bottom: 1em; padding: 0.5em 1em; }
</style>
</head>
<body>
<h1>Aptabase Standalone 테스트</h1>
<p>Click the buttons below to send test events.</p>
<button onclick="track('app_started')">Track: App Started</button>
<button onclick="track('feature_a_used', { plan: 'premium' })">Track: Used Feature A (with props)</button>
<button onclick="track('feature_b_used')">Track: Used Feature B</button>
<button onclick="track('user_signed_up')">Track: User Signed Up</button>
<button onclick="track('item_purchased', { item_id: 'SKU-123', price: 9.99 })">Track: Item Purchased (with props)</button>
<script>
// 1. Aptabase 초기화
// App Key의 region이 'SH'인 경우 host는 필수입니다.
window.aptabase.init("A-SH-7212023630", {
host: "https://aptabase.hmac.kr"
});
function track(eventName, props) {
// 2. 이벤트 전송
window.aptabase.trackEvent(eventName, props);
console.log(`Event '${eventName}' sent!`, props ? { props } : '');
}
</script>
</body>
</html>