@perkamo/browser 0.1.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/CHANGELOG.md +15 -0
- package/README.md +109 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +232 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# `@perkamo/browser` Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added browser-safe token client for planned client event/profile routes.
|
|
8
|
+
- Added lightweight progress widget mount helper.
|
|
9
|
+
- Added JSON-safe profile helpers and security guards for browser integrations.
|
|
10
|
+
|
|
11
|
+
## 0.1.1 - 2026-06-02
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Add a browser-safe client, JSON-safe profile helpers, stream-token support and progress widget helpers for public web integrations.
|
package/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# `@perkamo/browser`
|
|
2
|
+
|
|
3
|
+
Browser-safe Perkamo client and lightweight widget helpers.
|
|
4
|
+
|
|
5
|
+
Use this package only with short-lived tokens minted by your own backend. Never
|
|
6
|
+
put a Perkamo server API key in browser, mobile, or embedded widget code.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @perkamo/browser
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Client
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createPerkamoBrowserClient } from "@perkamo/browser";
|
|
16
|
+
|
|
17
|
+
const perkamo = createPerkamoBrowserClient({
|
|
18
|
+
baseUrl: "https://api.perkamo.com",
|
|
19
|
+
tenant: "commerce-test",
|
|
20
|
+
getToken: async () => {
|
|
21
|
+
const response = await fetch("/api/perkamo/token", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
credentials: "include",
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) throw new Error("Unable to create Perkamo token");
|
|
26
|
+
return (await response.json()).token;
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
await perkamo.emit("page.viewed", { path: location.pathname });
|
|
31
|
+
const profile = await perkamo.getProfileJson();
|
|
32
|
+
document.querySelector("#points").textContent = String(profile.wallets.points ?? 0);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The client calls browser-token routes:
|
|
36
|
+
|
|
37
|
+
- `POST /v1/client/events`
|
|
38
|
+
- `GET /v1/client/profile/me`
|
|
39
|
+
- `GET /v1/client/profile/me/stream`
|
|
40
|
+
|
|
41
|
+
These routes require a short-lived bearer token issued by the customer's backend.
|
|
42
|
+
The browser package rejects server-authoritative event context fields such as
|
|
43
|
+
`xp`, `wallet`, `wallets`, `level`, `perks`, `rewards` and `achievements`.
|
|
44
|
+
|
|
45
|
+
Profile helpers:
|
|
46
|
+
|
|
47
|
+
| Method | Purpose |
|
|
48
|
+
| ------------------ | ------------------------------------------------------------------------ |
|
|
49
|
+
| `getProfile()` | Returns the raw typed profile response from `GET /v1/client/profile/me`. |
|
|
50
|
+
| `profile()` | Alias for `getProfile()`. |
|
|
51
|
+
| `getProfileJson()` | Returns a JSON-safe profile snapshot for app/storefront rendering. |
|
|
52
|
+
| `profileJson()` | Alias for `getProfileJson()`. |
|
|
53
|
+
|
|
54
|
+
`getProfileJson()` omits `traits` by default because customer traits can contain
|
|
55
|
+
personal data. Opt in only when the current page needs them:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const profile = await perkamo.getProfileJson({ includeTraits: true });
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Security defaults:
|
|
62
|
+
|
|
63
|
+
- `baseUrl` must use HTTPS unless it is localhost or `allowInsecureHttp` is set
|
|
64
|
+
for local testing.
|
|
65
|
+
- Runtime options named `apiKey`, `serverApiKey`, `secret` or `signingSecret`
|
|
66
|
+
are rejected before any network request.
|
|
67
|
+
- Browser tokens should be kept in memory and refreshed through `getToken`.
|
|
68
|
+
- Profile streams require `getStreamToken` so a regular bearer token is not put
|
|
69
|
+
into an EventSource URL.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const perkamo = createPerkamoBrowserClient({
|
|
73
|
+
baseUrl: "https://api.perkamo.com",
|
|
74
|
+
tenant: "commerce-test",
|
|
75
|
+
getToken: () => fetchJson("/api/perkamo/token").then((body) => body.token),
|
|
76
|
+
getStreamToken: () =>
|
|
77
|
+
fetchJson("/api/perkamo/stream-token").then((body) => body.token),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const subscription = perkamo.subscribeProfile((profile) => {
|
|
81
|
+
renderProfile(profile);
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Progress Widget
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import {
|
|
89
|
+
createPerkamoBrowserClient,
|
|
90
|
+
mountPerkamoProgressWidget,
|
|
91
|
+
} from "@perkamo/browser";
|
|
92
|
+
|
|
93
|
+
const client = createPerkamoBrowserClient({
|
|
94
|
+
baseUrl: "https://api.perkamo.com",
|
|
95
|
+
tenant: "commerce-test",
|
|
96
|
+
getToken: () =>
|
|
97
|
+
fetch("/api/perkamo/token", { method: "POST" })
|
|
98
|
+
.then((r) => r.json())
|
|
99
|
+
.then((r) => r.token),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
mountPerkamoProgressWidget({
|
|
103
|
+
client,
|
|
104
|
+
target: "#perkamo-progress",
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The widget is intentionally small and unstyled. Customers should own the final
|
|
109
|
+
presentation in their app or storefront theme.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type EventIngestResponse, type PerkamoAchievements, type PerkamoEventContext, type PerkamoLevel, type PerkamoLevelProgress, type PerkamoNextPerk, type PerkamoProfile, type PerkamoProfileFlags, type PerkamoUnlockedPerk } from "@perkamo/sdk-core";
|
|
2
|
+
export { PerkamoApiError, type EventIngestResponse, type PerkamoProfile, } from "@perkamo/sdk-core";
|
|
3
|
+
export type BrowserTokenProvider = () => string | Promise<string>;
|
|
4
|
+
export type PerkamoBrowserClientOptions = {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
tenant: string;
|
|
7
|
+
getToken: BrowserTokenProvider;
|
|
8
|
+
getStreamToken?: BrowserTokenProvider;
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
allowInsecureHttp?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type BrowserEmitOptions = {
|
|
14
|
+
txId?: string;
|
|
15
|
+
occurredAt?: Date;
|
|
16
|
+
};
|
|
17
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
18
|
+
[key: string]: JsonValue;
|
|
19
|
+
};
|
|
20
|
+
export type JsonObject = {
|
|
21
|
+
[key: string]: JsonValue;
|
|
22
|
+
};
|
|
23
|
+
export type PerkamoProfileJsonOptions = {
|
|
24
|
+
/**
|
|
25
|
+
* Profile traits can contain customer-defined personal data. The browser JSON
|
|
26
|
+
* helper omits them unless the integration opts in explicitly.
|
|
27
|
+
*/
|
|
28
|
+
includeTraits?: boolean;
|
|
29
|
+
};
|
|
30
|
+
export type PerkamoProfileJson = {
|
|
31
|
+
user_id: string;
|
|
32
|
+
traits?: JsonObject;
|
|
33
|
+
wallets: Record<string, number>;
|
|
34
|
+
level: PerkamoLevel;
|
|
35
|
+
progress?: PerkamoLevelProgress;
|
|
36
|
+
perks: PerkamoUnlockedPerk[];
|
|
37
|
+
next_perks: PerkamoNextPerk[];
|
|
38
|
+
achievements: PerkamoAchievements;
|
|
39
|
+
flags: PerkamoProfileFlags;
|
|
40
|
+
};
|
|
41
|
+
export type PerkamoBrowserClient = {
|
|
42
|
+
emit(event: string, context?: PerkamoEventContext, options?: BrowserEmitOptions): Promise<EventIngestResponse>;
|
|
43
|
+
getProfile(): Promise<PerkamoProfile>;
|
|
44
|
+
profile(): Promise<PerkamoProfile>;
|
|
45
|
+
getProfileJson(options?: PerkamoProfileJsonOptions): Promise<PerkamoProfileJson>;
|
|
46
|
+
profileJson(options?: PerkamoProfileJsonOptions): Promise<PerkamoProfileJson>;
|
|
47
|
+
subscribeProfile(onProfile: (profile: PerkamoProfile) => void, onError?: (error: Event | Error) => void): {
|
|
48
|
+
close(): void;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export type PerkamoProgressWidgetOptions = {
|
|
52
|
+
client: PerkamoBrowserClient;
|
|
53
|
+
target: Element | string;
|
|
54
|
+
labels?: {
|
|
55
|
+
level?: string;
|
|
56
|
+
points?: string;
|
|
57
|
+
perks?: string;
|
|
58
|
+
loading?: string;
|
|
59
|
+
error?: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export declare function toProfileJson(profile: PerkamoProfile, options?: PerkamoProfileJsonOptions): PerkamoProfileJson;
|
|
63
|
+
export declare function createPerkamoBrowserClient(options: PerkamoBrowserClientOptions): PerkamoBrowserClient;
|
|
64
|
+
export declare function mountPerkamoProgressWidget(options: PerkamoProgressWidgetOptions): {
|
|
65
|
+
refresh(): Promise<void>;
|
|
66
|
+
destroy(): void;
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { PerkamoApiError, assertSafeEventInput, createTransactionId, } from "@perkamo/sdk-core";
|
|
2
|
+
export { PerkamoApiError, } from "@perkamo/sdk-core";
|
|
3
|
+
function requireFetch(customFetch) {
|
|
4
|
+
const fetcher = customFetch ?? globalThis.fetch;
|
|
5
|
+
if (!fetcher) {
|
|
6
|
+
throw new Error("@perkamo/browser requires fetch support");
|
|
7
|
+
}
|
|
8
|
+
return fetcher;
|
|
9
|
+
}
|
|
10
|
+
function assertNoServerSecrets(options) {
|
|
11
|
+
for (const key of ["apiKey", "serverApiKey", "secret", "signingSecret"]) {
|
|
12
|
+
if (key in options) {
|
|
13
|
+
throw new Error(`@perkamo/browser does not accept '${key}'. Mint short-lived browser tokens on your backend and pass getToken instead.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function assertSecureBaseUrl(baseUrl, allowInsecureHttp) {
|
|
18
|
+
const url = new URL(baseUrl);
|
|
19
|
+
if (url.protocol === "https:")
|
|
20
|
+
return;
|
|
21
|
+
const localHosts = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
22
|
+
if (url.protocol === "http:" && (allowInsecureHttp || localHosts.has(url.hostname))) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
throw new Error("@perkamo/browser requires an HTTPS baseUrl. Use allowInsecureHttp only for local development.");
|
|
26
|
+
}
|
|
27
|
+
function requireDocument() {
|
|
28
|
+
if (!globalThis.document) {
|
|
29
|
+
throw new Error("Perkamo widgets require a browser document");
|
|
30
|
+
}
|
|
31
|
+
return globalThis.document;
|
|
32
|
+
}
|
|
33
|
+
function requireEventSource() {
|
|
34
|
+
if (!globalThis.EventSource) {
|
|
35
|
+
throw new Error("Perkamo profile streams require EventSource support");
|
|
36
|
+
}
|
|
37
|
+
return globalThis.EventSource;
|
|
38
|
+
}
|
|
39
|
+
function fetchWithTimeout(fetcher, input, init, timeoutMs) {
|
|
40
|
+
if (!timeoutMs)
|
|
41
|
+
return fetcher(input, init);
|
|
42
|
+
const controller = new AbortController();
|
|
43
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
44
|
+
return fetcher(input, { ...init, signal: controller.signal }).finally(() => clearTimeout(timer));
|
|
45
|
+
}
|
|
46
|
+
async function throwIfError(response) {
|
|
47
|
+
if (response.ok)
|
|
48
|
+
return;
|
|
49
|
+
let body;
|
|
50
|
+
try {
|
|
51
|
+
body = await response.json();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
body = null;
|
|
55
|
+
}
|
|
56
|
+
throw new PerkamoApiError(response.status, body);
|
|
57
|
+
}
|
|
58
|
+
async function authorizationHeader(getToken) {
|
|
59
|
+
const token = await getToken();
|
|
60
|
+
if (!token.trim()) {
|
|
61
|
+
throw new Error("@perkamo/browser getToken returned an empty token");
|
|
62
|
+
}
|
|
63
|
+
return `Bearer ${token}`;
|
|
64
|
+
}
|
|
65
|
+
function cloneJsonValue(value) {
|
|
66
|
+
return JSON.parse(JSON.stringify(value));
|
|
67
|
+
}
|
|
68
|
+
function optionalJsonObject(value) {
|
|
69
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
70
|
+
return undefined;
|
|
71
|
+
return cloneJsonValue(value);
|
|
72
|
+
}
|
|
73
|
+
export function toProfileJson(profile, options = {}) {
|
|
74
|
+
return {
|
|
75
|
+
user_id: profile.user_id,
|
|
76
|
+
...(options.includeTraits
|
|
77
|
+
? { traits: optionalJsonObject(profile.traits) ?? {} }
|
|
78
|
+
: {}),
|
|
79
|
+
wallets: cloneJsonValue(profile.wallets),
|
|
80
|
+
level: cloneJsonValue(profile.level),
|
|
81
|
+
...(profile.progress ? { progress: cloneJsonValue(profile.progress) } : {}),
|
|
82
|
+
perks: cloneJsonValue(profile.perks),
|
|
83
|
+
next_perks: cloneJsonValue(profile.next_perks),
|
|
84
|
+
achievements: cloneJsonValue(profile.achievements),
|
|
85
|
+
flags: cloneJsonValue(profile.flags),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function createPerkamoBrowserClient(options) {
|
|
89
|
+
assertNoServerSecrets(options);
|
|
90
|
+
assertSecureBaseUrl(options.baseUrl, options.allowInsecureHttp === true);
|
|
91
|
+
const fetcher = requireFetch(options.fetch);
|
|
92
|
+
const baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
93
|
+
async function go(input, init) {
|
|
94
|
+
return fetchWithTimeout(fetcher, input, init, options.timeoutMs);
|
|
95
|
+
}
|
|
96
|
+
async function headers(withBody = false) {
|
|
97
|
+
return {
|
|
98
|
+
...(withBody ? { "content-type": "application/json" } : {}),
|
|
99
|
+
authorization: await authorizationHeader(options.getToken),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function getProfile() {
|
|
103
|
+
const response = await go(`${baseUrl}/v1/client/profile/me`, {
|
|
104
|
+
headers: await headers(),
|
|
105
|
+
});
|
|
106
|
+
await throwIfError(response);
|
|
107
|
+
return response.json();
|
|
108
|
+
}
|
|
109
|
+
async function getProfileJson(profileOptions = {}) {
|
|
110
|
+
return toProfileJson(await getProfile(), profileOptions);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
async emit(event, context = {}, emitOptions = {}) {
|
|
114
|
+
const input = {
|
|
115
|
+
tenant: options.tenant,
|
|
116
|
+
user_id: "me",
|
|
117
|
+
event,
|
|
118
|
+
transaction_id: emitOptions.txId ?? createTransactionId(),
|
|
119
|
+
context,
|
|
120
|
+
occurred_at: (emitOptions.occurredAt ?? new Date()).toISOString(),
|
|
121
|
+
};
|
|
122
|
+
assertSafeEventInput(input);
|
|
123
|
+
const response = await go(`${baseUrl}/v1/client/events`, {
|
|
124
|
+
method: "POST",
|
|
125
|
+
headers: await headers(true),
|
|
126
|
+
body: JSON.stringify({
|
|
127
|
+
event: input.event,
|
|
128
|
+
transaction_id: input.transaction_id,
|
|
129
|
+
context: input.context,
|
|
130
|
+
occurred_at: input.occurred_at,
|
|
131
|
+
}),
|
|
132
|
+
});
|
|
133
|
+
await throwIfError(response);
|
|
134
|
+
return response.json();
|
|
135
|
+
},
|
|
136
|
+
getProfile,
|
|
137
|
+
profile: getProfile,
|
|
138
|
+
getProfileJson,
|
|
139
|
+
profileJson: getProfileJson,
|
|
140
|
+
subscribeProfile(onProfile, onError) {
|
|
141
|
+
if (!options.getStreamToken) {
|
|
142
|
+
throw new Error("@perkamo/browser profile streams require getStreamToken so regular bearer tokens are not placed in URLs");
|
|
143
|
+
}
|
|
144
|
+
const EventSourceCtor = requireEventSource();
|
|
145
|
+
const url = new URL(`${baseUrl}/v1/client/profile/me/stream`);
|
|
146
|
+
url.searchParams.set("tenant", options.tenant);
|
|
147
|
+
let closed = false;
|
|
148
|
+
let source = null;
|
|
149
|
+
void Promise.resolve(options.getStreamToken())
|
|
150
|
+
.then((token) => {
|
|
151
|
+
if (closed)
|
|
152
|
+
return;
|
|
153
|
+
if (!token.trim()) {
|
|
154
|
+
throw new Error("@perkamo/browser getStreamToken returned an empty token");
|
|
155
|
+
}
|
|
156
|
+
url.searchParams.set("token", token);
|
|
157
|
+
source = new EventSourceCtor(url.toString());
|
|
158
|
+
source.onmessage = (event) => {
|
|
159
|
+
try {
|
|
160
|
+
onProfile(JSON.parse(event.data));
|
|
161
|
+
}
|
|
162
|
+
catch (caught) {
|
|
163
|
+
onError?.(caught instanceof Error
|
|
164
|
+
? caught
|
|
165
|
+
: new Error("Perkamo profile stream message could not be parsed"));
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
source.onerror = (event) => onError?.(event);
|
|
169
|
+
})
|
|
170
|
+
.catch((error) => onError?.(error instanceof Error ? error : new Error(String(error))));
|
|
171
|
+
return {
|
|
172
|
+
close() {
|
|
173
|
+
closed = true;
|
|
174
|
+
source?.close();
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function resolveTarget(target) {
|
|
181
|
+
if (typeof target !== "string")
|
|
182
|
+
return target;
|
|
183
|
+
const element = requireDocument().querySelector(target);
|
|
184
|
+
if (!element) {
|
|
185
|
+
throw new Error(`Perkamo widget target '${target}' was not found`);
|
|
186
|
+
}
|
|
187
|
+
return element;
|
|
188
|
+
}
|
|
189
|
+
function renderProfile(target, profile, labels) {
|
|
190
|
+
const level = profile.level;
|
|
191
|
+
const points = Object.entries(profile.wallets)
|
|
192
|
+
.map(([wallet, value]) => `${wallet}: ${value}`)
|
|
193
|
+
.join(" · ");
|
|
194
|
+
target.textContent = [
|
|
195
|
+
`${labels.level} ${level.level}`,
|
|
196
|
+
`${labels.points}: ${points || "0"}`,
|
|
197
|
+
`${labels.perks}: ${profile.perks.length}`,
|
|
198
|
+
].join("\n");
|
|
199
|
+
}
|
|
200
|
+
export function mountPerkamoProgressWidget(options) {
|
|
201
|
+
const target = resolveTarget(options.target);
|
|
202
|
+
const labels = {
|
|
203
|
+
level: options.labels?.level ?? "Level",
|
|
204
|
+
points: options.labels?.points ?? "Points",
|
|
205
|
+
perks: options.labels?.perks ?? "Perks",
|
|
206
|
+
loading: options.labels?.loading ?? "Loading Perkamo profile...",
|
|
207
|
+
error: options.labels?.error ?? "Unable to load Perkamo profile.",
|
|
208
|
+
};
|
|
209
|
+
let destroyed = false;
|
|
210
|
+
async function refresh() {
|
|
211
|
+
target.textContent = labels.loading;
|
|
212
|
+
try {
|
|
213
|
+
const profile = await options.client.profile();
|
|
214
|
+
if (!destroyed)
|
|
215
|
+
renderProfile(target, profile, labels);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
if (!destroyed)
|
|
219
|
+
target.textContent = labels.error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
void refresh();
|
|
223
|
+
return {
|
|
224
|
+
refresh,
|
|
225
|
+
destroy() {
|
|
226
|
+
destroyed = true;
|
|
227
|
+
target.textContent = "";
|
|
228
|
+
target.innerHTML = "";
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@perkamo/browser",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Browser-safe Perkamo client and widget helpers.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20.0.0"
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json",
|
|
29
|
+
"test": "vitest run src",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
31
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
32
|
+
"format": "prettier --write src",
|
|
33
|
+
"format:check": "prettier --check src"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@perkamo/sdk-core": "0.1.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"vitest": "4.1.7"
|
|
40
|
+
}
|
|
41
|
+
}
|