feat: sdks and docs (#239)
* init * fix * update docs * bump: all sdks * rename types test
This commit is contained in:
committed by
GitHub
parent
790801b728
commit
83e223a496
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openpanel/astro",
|
||||
"version": "1.0.2-local",
|
||||
"version": "1.0.3-local",
|
||||
"config": {
|
||||
"transformPackageJson": false,
|
||||
"transformEnvs": true
|
||||
@@ -14,7 +14,7 @@
|
||||
"files": ["src", "index.ts"],
|
||||
"keywords": ["astro-component"],
|
||||
"dependencies": {
|
||||
"@openpanel/web": "workspace:1.0.2-local"
|
||||
"@openpanel/web": "workspace:1.0.3-local"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "^5.7.7"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
import type { OpenPanelMethodNames, OpenPanelOptions } from '@openpanel/web';
|
||||
import { getInitSnippet } from '@openpanel/web';
|
||||
|
||||
type Props = Omit<OpenPanelOptions, 'filter'> & {
|
||||
profileId?: string;
|
||||
@@ -32,7 +33,7 @@ const methods: { name: OpenPanelMethodNames; value: unknown }[] = [
|
||||
value: {
|
||||
...options,
|
||||
sdk: 'astro',
|
||||
sdkVersion: '1.0.2',
|
||||
sdkVersion: '1.0.3',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -51,7 +52,7 @@ if (globalProperties) {
|
||||
});
|
||||
}
|
||||
|
||||
const scriptContent = `window.op = window.op || function(...args) {(window.op.q = window.op.q || []).push(args)};
|
||||
const scriptContent = `${getInitSnippet()}
|
||||
${methods
|
||||
.map((method) => {
|
||||
return `window.op('${method.name}', ${stringify(method.value)});`;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@openpanel/express",
|
||||
"version": "1.0.1-local",
|
||||
"version": "1.0.2-local",
|
||||
"module": "index.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsup",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openpanel/sdk": "workspace:1.0.0-local",
|
||||
"@openpanel/sdk": "workspace:1.0.1-local",
|
||||
"@openpanel/common": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@openpanel/tsconfig/base.json",
|
||||
"extends": "@openpanel/tsconfig/sdk.json",
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
OpenPanelOptions,
|
||||
TrackProperties,
|
||||
} from '@openpanel/web';
|
||||
import { getInitSnippet } from '@openpanel/web';
|
||||
|
||||
export * from '@openpanel/web';
|
||||
|
||||
@@ -73,7 +74,7 @@ export function OpenPanelComponent({
|
||||
<Script
|
||||
strategy="beforeInteractive"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window.op = window.op || function(...args) {(window.op.q = window.op.q || []).push(args)};
|
||||
__html: `${getInitSnippet()}
|
||||
${methods
|
||||
.map((method) => {
|
||||
return `window.op('${method.name}', ${stringify(method.value)});`;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@openpanel/nextjs",
|
||||
"version": "1.0.15-local",
|
||||
"version": "1.0.16-local",
|
||||
"module": "index.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsup",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openpanel/web": "workspace:1.0.2-local"
|
||||
"@openpanel/web": "workspace:1.0.3-local"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@openpanel/tsconfig/base.json",
|
||||
"extends": "@openpanel/tsconfig/sdk.json",
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@openpanel/react-native",
|
||||
"version": "1.0.1-local",
|
||||
"version": "1.0.2-local",
|
||||
"module": "index.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsup",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openpanel/sdk": "workspace:1.0.0-local"
|
||||
"@openpanel/sdk": "workspace:1.0.1-local"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openpanel/tsconfig": "workspace:*",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@openpanel/tsconfig/base.json",
|
||||
"extends": "@openpanel/tsconfig/sdk.json",
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openpanel/sdk",
|
||||
"version": "1.0.0-local",
|
||||
"version": "1.0.1-local",
|
||||
"module": "index.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsup",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@openpanel/tsconfig/base.json",
|
||||
"extends": "@openpanel/tsconfig/sdk.json",
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './src/index';
|
||||
export * from './src/types.d';
|
||||
export { getInitSnippet } from './src/init-snippet';
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "@openpanel/web",
|
||||
"version": "1.0.2-local",
|
||||
"version": "1.0.3-local",
|
||||
"module": "index.ts",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist && tsup",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openpanel/sdk": "workspace:1.0.0-local"
|
||||
"@openpanel/sdk": "workspace:1.0.1-local"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@openpanel/tsconfig": "workspace:*",
|
||||
|
||||
23
packages/sdks/web/src/init-snippet.ts
Normal file
23
packages/sdks/web/src/init-snippet.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// Source:
|
||||
// window.op = window.op || (function() {
|
||||
// var q = [];
|
||||
// var op = new Proxy(function() {
|
||||
// if (arguments.length > 0) {
|
||||
// q.push(Array.prototype.slice.call(arguments));
|
||||
// }
|
||||
// }, {
|
||||
// get: function(_, prop) {
|
||||
// if (prop === 'q') {
|
||||
// return q;
|
||||
// }
|
||||
// return function() {
|
||||
// q.push([prop].concat(Array.prototype.slice.call(arguments)));
|
||||
// };
|
||||
// }
|
||||
// });
|
||||
// return op;
|
||||
// })();
|
||||
|
||||
export function getInitSnippet(): string {
|
||||
return `window.op=window.op||function(){var n=[],o=new Proxy((function(){arguments.length>0&&n.push(Array.prototype.slice.call(arguments))}),{get:function(o,t){return"q"===t?n:function(){n.push([t].concat(Array.prototype.slice.call(arguments)))}}});return o}();`;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { OpenPanel } from './index';
|
||||
|
||||
((window) => {
|
||||
if (window.op && 'q' in window.op) {
|
||||
if (window.op) {
|
||||
const queue = window.op.q || [];
|
||||
// @ts-expect-error
|
||||
const op = new OpenPanel(queue.shift()[1]);
|
||||
@@ -12,16 +12,36 @@ import { OpenPanel } from './index';
|
||||
}
|
||||
});
|
||||
|
||||
window.op = (t, ...args) => {
|
||||
const fn = op[t] ? op[t].bind(op) : undefined;
|
||||
if (typeof fn === 'function') {
|
||||
// @ts-expect-error
|
||||
fn(...args);
|
||||
} else {
|
||||
console.warn(`OpenPanel: ${t} is not a function`);
|
||||
}
|
||||
};
|
||||
// Create a Proxy that supports both window.op('track', ...) and window.op.track(...)
|
||||
const opCallable = new Proxy(
|
||||
((method: string, ...args: any[]) => {
|
||||
const fn = (op as any)[method]
|
||||
? (op as any)[method].bind(op)
|
||||
: undefined;
|
||||
if (typeof fn === 'function') {
|
||||
fn(...args);
|
||||
} else {
|
||||
console.warn(`OpenPanel: ${method} is not a function`);
|
||||
}
|
||||
}) as typeof op & ((method: string, ...args: any[]) => void),
|
||||
{
|
||||
get(target, prop) {
|
||||
// Handle special properties
|
||||
if (prop === 'q') {
|
||||
return undefined; // q doesn't exist after SDK loads
|
||||
}
|
||||
// If accessing a method on op, return the bound method
|
||||
const value = (op as any)[prop];
|
||||
if (typeof value === 'function') {
|
||||
return value.bind(op);
|
||||
}
|
||||
// Otherwise return the property from op (for things like options, etc.)
|
||||
return value;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
window.op = opCallable;
|
||||
window.openpanel = op;
|
||||
}
|
||||
})(window);
|
||||
|
||||
28
packages/sdks/web/src/types.d.ts
vendored
28
packages/sdks/web/src/types.d.ts
vendored
@@ -12,7 +12,9 @@ type ExposedMethodsNames =
|
||||
| 'revenue'
|
||||
| 'flushRevenue'
|
||||
| 'clearRevenue'
|
||||
| 'pendingRevenue';
|
||||
| 'pendingRevenue'
|
||||
| 'screenView'
|
||||
| 'fetchDeviceId';
|
||||
|
||||
export type ExposedMethods = {
|
||||
[K in ExposedMethodsNames]: OpenPanel[K] extends (...args: any[]) => any
|
||||
@@ -20,7 +22,7 @@ export type ExposedMethods = {
|
||||
: never;
|
||||
}[ExposedMethodsNames];
|
||||
|
||||
export type OpenPanelMethodNames = ExposedMethodsNames | 'init' | 'screenView';
|
||||
export type OpenPanelMethodNames = ExposedMethodsNames | 'init';
|
||||
export type OpenPanelMethods =
|
||||
| ExposedMethods
|
||||
| ['init', OpenPanelOptions]
|
||||
@@ -30,12 +32,26 @@ export type OpenPanelMethods =
|
||||
TrackProperties | undefined,
|
||||
];
|
||||
|
||||
// Extract method signatures from OpenPanel for direct method calls
|
||||
type OpenPanelMethodSignatures = {
|
||||
[K in ExposedMethodsNames]: OpenPanel[K];
|
||||
} & {
|
||||
screenView(
|
||||
pathOrProperties?: string | TrackProperties,
|
||||
properties?: TrackProperties,
|
||||
): void;
|
||||
};
|
||||
|
||||
// Create a type that supports both callable and direct method access
|
||||
type OpenPanelAPI = OpenPanelMethodSignatures & {
|
||||
q?: OpenPanelMethods[];
|
||||
// Callable function API: window.op('track', 'event', {...})
|
||||
(...args: OpenPanelMethods): void;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
openpanel?: OpenPanel;
|
||||
op: {
|
||||
q?: OpenPanelMethods[];
|
||||
(...args: OpenPanelMethods): void;
|
||||
};
|
||||
op: OpenPanelAPI;
|
||||
}
|
||||
}
|
||||
|
||||
89
packages/sdks/web/src/types.debug.ts
Normal file
89
packages/sdks/web/src/types.debug.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
// Test callable function API
|
||||
function testCallableAPI() {
|
||||
// ✅ Should work - correct callable syntax
|
||||
window.op('track', 'button_clicked', { location: 'header' });
|
||||
window.op('identify', { profileId: 'user123', email: 'test@example.com' });
|
||||
window.op('init', { clientId: 'test-client-id' });
|
||||
window.op('screenView', '/page', { title: 'Test Page' });
|
||||
window.op('setGlobalProperties', { version: '1.0.0' });
|
||||
|
||||
// ❌ Should error - wrong method name
|
||||
// @ts-expect-error - 'invalidMethod' is not a valid method
|
||||
window.op('invalidMethod', 'test');
|
||||
|
||||
// ❌ Should error - wrong arguments for track
|
||||
// @ts-expect-error - track expects (name: string, properties?: TrackProperties)
|
||||
window.op('track', 123);
|
||||
}
|
||||
|
||||
// Test direct method API
|
||||
function testDirectMethodAPI() {
|
||||
// ✅ Should work - correct direct method syntax
|
||||
window.op.track('button_clicked', { location: 'header' });
|
||||
window.op.identify({ profileId: 'user123', email: 'test@example.com' });
|
||||
window.op.screenView('/page', { title: 'Test Page' });
|
||||
window.op.screenView({ title: 'Test Page' }); // Overload with just properties
|
||||
window.op.setGlobalProperties({ version: '1.0.0' });
|
||||
window.op.revenue(1000, { currency: 'USD' });
|
||||
window.op.pendingRevenue(500, { productId: '123' });
|
||||
window.op.flushRevenue();
|
||||
window.op.clearRevenue();
|
||||
window.op.fetchDeviceId();
|
||||
|
||||
// ❌ Should error - wrong arguments for track
|
||||
// @ts-expect-error - track expects (name: string, properties?: TrackProperties)
|
||||
window.op.track(123);
|
||||
|
||||
// ❌ Should error - wrong arguments for identify
|
||||
// @ts-expect-error - identify expects IdentifyPayload
|
||||
window.op.identify('user123');
|
||||
}
|
||||
|
||||
// Test queue property
|
||||
function testQueueProperty() {
|
||||
// ✅ Should work - q is optional and can be accessed
|
||||
const queue = window.op.q;
|
||||
if (queue) {
|
||||
queue.forEach((item) => {
|
||||
// Queue items should be properly typed
|
||||
if (item[0] === 'track') {
|
||||
const eventName = item[1]; // Should be string
|
||||
const properties = item[2]; // Should be TrackProperties | undefined
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Test that both APIs work together
|
||||
function testBothAPIs() {
|
||||
// Mix and match - both should work
|
||||
window.op('track', 'event1', { prop: 'value' });
|
||||
window.op.track('event2', { prop: 'value' });
|
||||
window.op('identify', { profileId: '123' });
|
||||
window.op.identify({ profileId: '456' });
|
||||
}
|
||||
|
||||
// Test autocomplete and type inference
|
||||
function testTypeInference() {
|
||||
// TypeScript should infer the correct types
|
||||
const trackCall = window.op.track;
|
||||
// trackCall should be: (name: string, properties?: TrackProperties) => Promise<void>
|
||||
|
||||
const identifyCall = window.op.identify;
|
||||
// identifyCall should be: (payload: IdentifyPayload) => Promise<void>
|
||||
|
||||
// Callable function should accept OpenPanelMethods
|
||||
const callable = window.op;
|
||||
// callable should be callable with OpenPanelMethods
|
||||
}
|
||||
|
||||
function testExpectedErrors() {
|
||||
// @ts-expect-error - 'invalidMethod' is not a valid method
|
||||
window.op('invalidMethod', 'test');
|
||||
// @ts-expect-error - track expects (name: string, properties?: TrackProperties)
|
||||
window.op.track(123);
|
||||
// @ts-expect-error - identify expects IdentifyPayload
|
||||
window.op.identify('user123');
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "@openpanel/tsconfig/base.json",
|
||||
"extends": "@openpanel/tsconfig/sdk.json",
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"outDir": "dist"
|
||||
|
||||
Reference in New Issue
Block a user