@perkamo/sdk 0.1.0
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 +22 -0
- package/README.md +90 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/package.json +41 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Initial public JavaScript and TypeScript SDK package for trusted backend
|
|
8
|
+
integrations.
|
|
9
|
+
- Added `createPerkamoClient` with `emit`, `batch`, `profile` and preview
|
|
10
|
+
`subscribeProfile` helpers.
|
|
11
|
+
- Added automatic tenant API key headers for server-side REST calls.
|
|
12
|
+
- Added automatic HMAC request signatures for mutating event ingestion calls.
|
|
13
|
+
- Added configurable `fetch` adapter and request timeout support.
|
|
14
|
+
- Re-exported shared public response and profile types from `@perkamo/sdk-core`.
|
|
15
|
+
|
|
16
|
+
### Security
|
|
17
|
+
|
|
18
|
+
- Signs mutating API requests with `x-perkamo-timestamp` and
|
|
19
|
+
`x-perkamo-signature`, binding the HTTP method, path and raw JSON body to the
|
|
20
|
+
server API key.
|
|
21
|
+
- Keeps tenant server API keys as backend-only configuration; browser/profile
|
|
22
|
+
stream support requires short-lived tokens and remains preview-labeled.
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# `@perkamo/sdk`
|
|
2
|
+
|
|
3
|
+
Server-side JavaScript and TypeScript client for the Perkamo API.
|
|
4
|
+
|
|
5
|
+
See the full customer developer guide in
|
|
6
|
+
[`../../docs/sdk-api.md`](../../docs/sdk-api.md).
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { createPerkamoClient } from "@perkamo/sdk";
|
|
12
|
+
|
|
13
|
+
const perkamo = createPerkamoClient({
|
|
14
|
+
baseUrl: "https://api.perkamo.com",
|
|
15
|
+
tenant: "commerce-test",
|
|
16
|
+
apiKey: () => process.env.PERKAMO_SECRET_KEY,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const result = await perkamo.emit(
|
|
20
|
+
"customer_123",
|
|
21
|
+
"purchase.completed",
|
|
22
|
+
{
|
|
23
|
+
order_id: "order_1092",
|
|
24
|
+
amount: 12900,
|
|
25
|
+
currency: "CZK",
|
|
26
|
+
},
|
|
27
|
+
{ txId: "order_1092" },
|
|
28
|
+
);
|
|
29
|
+
// result: EventIngestResponse — delta, wallet_state, level, unlocked, …
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
### `createPerkamoClient(options): PerkamoClient`
|
|
35
|
+
|
|
36
|
+
| Option | Type | Description |
|
|
37
|
+
| ----------- | ------------------------------------------- | -------------------------------------------- |
|
|
38
|
+
| `baseUrl` | `string` | API base URL, e.g. `https://api.perkamo.com` |
|
|
39
|
+
| `tenant` | `string` | Space slug, e.g. `commerce-test` |
|
|
40
|
+
| `apiKey` | `string \| () => string \| Promise<string>` | Server API key — never in browser code |
|
|
41
|
+
| `fetch` | `typeof fetch` | Custom fetch for tests or edge runtimes |
|
|
42
|
+
| `timeoutMs` | `number` | Request timeout in milliseconds |
|
|
43
|
+
|
|
44
|
+
### `client.emit(userId, event, context?, options?): Promise<EventIngestResponse>`
|
|
45
|
+
|
|
46
|
+
Sends one activity event to `POST /v1/events`. Auto-generates a transaction ID when `options.txId` is omitted.
|
|
47
|
+
|
|
48
|
+
### `client.batch(events): Promise<BatchIngestResponse>`
|
|
49
|
+
|
|
50
|
+
Sends up to 100 events in one request to `POST /v1/events:batch`. Each event requires an explicit `transaction_id`. The client `tenant` is injected when `event.tenant` is omitted.
|
|
51
|
+
|
|
52
|
+
### `client.profile(userId): Promise<PerkamoProfile>`
|
|
53
|
+
|
|
54
|
+
Reads the current server-authoritative profile from `GET /v1/profile/{userId}`.
|
|
55
|
+
|
|
56
|
+
### `client.subscribeProfile(userId, streamToken, onProfile, onError?): ProfileSubscription`
|
|
57
|
+
|
|
58
|
+
Preview helper for the planned profile SSE stream flow. Do not treat this as a stable v1 server API contract yet; the stable v1 public HTTP API is backend-first. When profile streams are enabled for an integration, they require a short-lived stream token minted by your backend — never pass tenant API keys to browser subscriptions.
|
|
59
|
+
|
|
60
|
+
### `PerkamoApiError`
|
|
61
|
+
|
|
62
|
+
Thrown on non-2xx responses. Has `status: number` and `body: unknown` properties.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { PerkamoApiError } from "@perkamo/sdk";
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
await perkamo.emit("user", "event");
|
|
69
|
+
} catch (err) {
|
|
70
|
+
if (err instanceof PerkamoApiError) {
|
|
71
|
+
console.error(err.status, err.body);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Reserved context fields
|
|
77
|
+
|
|
78
|
+
The SDK rejects context keys that Perkamo computes server-side: `xp`, `wallet`, `wallets`, `rewards`, `level`, `perks`, `achievements`. Use event context only for business facts (order ID, amount, category).
|
|
79
|
+
|
|
80
|
+
## Security
|
|
81
|
+
|
|
82
|
+
Server API keys belong only in your backend or secret manager — never in browser,
|
|
83
|
+
mobile, or embedded widget code. Browser-token key metadata and allowed request
|
|
84
|
+
origins are separate from customer-site CSP, but client-safe browser routes and
|
|
85
|
+
profile stream token verification are preview work rather than stable v1 API
|
|
86
|
+
surface.
|
|
87
|
+
|
|
88
|
+
The SDK automatically signs mutating API requests with
|
|
89
|
+
`x-perkamo-timestamp` and `x-perkamo-signature`, binding the method, path and
|
|
90
|
+
raw JSON body to the server API key.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { type BatchIngestResponse, type EventIngestResponse, type PerkamoEventContext, type PerkamoProfile } from "@perkamo/sdk-core";
|
|
2
|
+
export { PerkamoApiError, type BatchIngestResponse, type EventIngestResponse, type PerkamoProfile, type WalletDelta, type PerkamoLevel, type PerkamoUnlockedPerk, type PerkamoProfileFlags, } from "@perkamo/sdk-core";
|
|
3
|
+
export type PerkamoClientOptions = {
|
|
4
|
+
/** Perkamo API base URL, e.g. `https://api.perkamo.com`. */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Space slug, e.g. `commerce-test`. Must match the API key's Space. */
|
|
7
|
+
tenant: string;
|
|
8
|
+
/**
|
|
9
|
+
* Server API key or an async function that returns one.
|
|
10
|
+
* Keep server keys in backend environment variables — never in browser code.
|
|
11
|
+
*/
|
|
12
|
+
apiKey?: string | (() => string | Promise<string>);
|
|
13
|
+
/** Custom fetch implementation for tests or runtimes without global fetch. */
|
|
14
|
+
fetch?: typeof fetch;
|
|
15
|
+
/** Request timeout in milliseconds. Default: no timeout. */
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
};
|
|
18
|
+
export type EmitOptions = {
|
|
19
|
+
/**
|
|
20
|
+
* Idempotency key. Use a stable business ID (order ID, booking ID, …).
|
|
21
|
+
* The SDK generates a UUID when omitted — safe for low-stakes events.
|
|
22
|
+
*/
|
|
23
|
+
txId?: string;
|
|
24
|
+
/** Event timestamp. Defaults to current time when omitted. */
|
|
25
|
+
occurredAt?: Date;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A single event for `batch()`. `tenant` is optional — when omitted it
|
|
29
|
+
* inherits from the client's configured `tenant`.
|
|
30
|
+
*/
|
|
31
|
+
export type BatchEventInput = {
|
|
32
|
+
user_id: string;
|
|
33
|
+
event: string;
|
|
34
|
+
/** Idempotency key. Required — unlike `emit()`, batch does not auto-generate. */
|
|
35
|
+
transaction_id: string;
|
|
36
|
+
/** Overrides the client tenant for this event. Rarely needed. */
|
|
37
|
+
tenant?: string;
|
|
38
|
+
context?: PerkamoEventContext;
|
|
39
|
+
occurred_at?: string;
|
|
40
|
+
};
|
|
41
|
+
export type ProfileSubscription = {
|
|
42
|
+
close(): void;
|
|
43
|
+
};
|
|
44
|
+
export type PerkamoClient = {
|
|
45
|
+
/**
|
|
46
|
+
* Sends one activity event to `POST /v1/events`.
|
|
47
|
+
*
|
|
48
|
+
* @param userId Your stable user identifier.
|
|
49
|
+
* @param event Stable event name, e.g. `purchase.completed`.
|
|
50
|
+
* @param context Supporting facts. Do not include computed state fields.
|
|
51
|
+
* @param options Override transaction ID or event timestamp.
|
|
52
|
+
*/
|
|
53
|
+
emit(userId: string, event: string, context?: PerkamoEventContext, options?: EmitOptions): Promise<EventIngestResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Sends up to 100 events in one request to `POST /v1/events:batch`.
|
|
56
|
+
* Each event requires an explicit `transaction_id`.
|
|
57
|
+
* `tenant` defaults to the client's configured `tenant` when omitted.
|
|
58
|
+
*/
|
|
59
|
+
batch(events: BatchEventInput[]): Promise<BatchIngestResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Reads the current server-authoritative profile state from
|
|
62
|
+
* `GET /v1/profile/{userId}`.
|
|
63
|
+
*/
|
|
64
|
+
profile(userId: string): Promise<PerkamoProfile>;
|
|
65
|
+
/**
|
|
66
|
+
* Opens a profile SSE stream with a short-lived stream token minted by the
|
|
67
|
+
* customer backend. Never pass tenant API keys to browser subscriptions.
|
|
68
|
+
*/
|
|
69
|
+
subscribeProfile(userId: string, streamToken: string, onProfile: (profile: PerkamoProfile) => void, onError?: (error: Event | Error) => void): ProfileSubscription;
|
|
70
|
+
};
|
|
71
|
+
export type PerkamoRequestSignatureInput = {
|
|
72
|
+
apiKey: string;
|
|
73
|
+
timestamp: string;
|
|
74
|
+
method: string;
|
|
75
|
+
path: string;
|
|
76
|
+
body: string;
|
|
77
|
+
};
|
|
78
|
+
export declare function createPerkamoRequestSignature(input: PerkamoRequestSignatureInput): Promise<string>;
|
|
79
|
+
export declare function createPerkamoClient(options: PerkamoClientOptions): PerkamoClient;
|
|
80
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EAExB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,GACzB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,MAAM,oBAAoB,GAAG;IACjC,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACnD,8EAA8E;IAC9E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,UAAU,CAAC,EAAE,IAAI,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,cAAc,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAIF,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;;;;OAOG;IACH,IAAI,CACF,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,mBAAmB,EAC7B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAEhC;;;;OAIG;IACH,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAE/D;;;OAGG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEjD;;;OAGG;IACH,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,EAC5C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,KAAK,IAAI,GACvC,mBAAmB,CAAC;CACxB,CAAC;AAMF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AA2BF,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAqED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAqGhF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { assertSafeEventInput, createTransactionId, PerkamoApiError, } from "@perkamo/sdk-core";
|
|
2
|
+
export { PerkamoApiError, } from "@perkamo/sdk-core";
|
|
3
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
4
|
+
const signatureVersion = "v1";
|
|
5
|
+
async function resolveApiKey(apiKey) {
|
|
6
|
+
return typeof apiKey === "function" ? apiKey() : apiKey;
|
|
7
|
+
}
|
|
8
|
+
function bytesToHex(bytes) {
|
|
9
|
+
return Array.from(bytes)
|
|
10
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
11
|
+
.join("");
|
|
12
|
+
}
|
|
13
|
+
async function sha256Hex(value) {
|
|
14
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
15
|
+
return bytesToHex(new Uint8Array(digest));
|
|
16
|
+
}
|
|
17
|
+
function requestPath(input) {
|
|
18
|
+
const url = new URL(input);
|
|
19
|
+
return `${url.pathname}${url.search}`;
|
|
20
|
+
}
|
|
21
|
+
export async function createPerkamoRequestSignature(input) {
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
const key = await globalThis.crypto.subtle.importKey("raw", encoder.encode(input.apiKey), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
|
|
24
|
+
const baseString = [
|
|
25
|
+
signatureVersion,
|
|
26
|
+
input.timestamp,
|
|
27
|
+
input.method.toUpperCase(),
|
|
28
|
+
input.path,
|
|
29
|
+
await sha256Hex(input.body),
|
|
30
|
+
].join(".");
|
|
31
|
+
const signature = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(baseString));
|
|
32
|
+
return `${signatureVersion}=${bytesToHex(new Uint8Array(signature))}`;
|
|
33
|
+
}
|
|
34
|
+
async function authorizedHeaders(options, withBody = false, signedRequest) {
|
|
35
|
+
const headers = {};
|
|
36
|
+
if (withBody)
|
|
37
|
+
headers["content-type"] = "application/json";
|
|
38
|
+
const apiKey = await resolveApiKey(options.apiKey);
|
|
39
|
+
if (apiKey) {
|
|
40
|
+
headers["x-perkamo-api-key"] = apiKey;
|
|
41
|
+
if (signedRequest) {
|
|
42
|
+
const timestamp = String(Math.floor(Date.now() / 1000));
|
|
43
|
+
headers["x-perkamo-timestamp"] = timestamp;
|
|
44
|
+
headers["x-perkamo-signature"] = await createPerkamoRequestSignature({
|
|
45
|
+
apiKey,
|
|
46
|
+
timestamp,
|
|
47
|
+
method: signedRequest.method,
|
|
48
|
+
path: requestPath(signedRequest.input),
|
|
49
|
+
body: signedRequest.body,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return headers;
|
|
54
|
+
}
|
|
55
|
+
function requireFetch(customFetch) {
|
|
56
|
+
const fetcher = customFetch ?? globalThis.fetch;
|
|
57
|
+
if (!fetcher) {
|
|
58
|
+
throw new Error("Perkamo SDK requires fetch or a fetch-compatible adapter");
|
|
59
|
+
}
|
|
60
|
+
return fetcher;
|
|
61
|
+
}
|
|
62
|
+
function fetchWithTimeout(fetcher, input, init, timeoutMs) {
|
|
63
|
+
if (!timeoutMs)
|
|
64
|
+
return fetcher(input, init);
|
|
65
|
+
const controller = new AbortController();
|
|
66
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
67
|
+
return fetcher(input, { ...init, signal: controller.signal }).finally(() => clearTimeout(timer));
|
|
68
|
+
}
|
|
69
|
+
function requireEventSource() {
|
|
70
|
+
if (!globalThis.EventSource) {
|
|
71
|
+
throw new Error("Perkamo profile subscriptions require EventSource support");
|
|
72
|
+
}
|
|
73
|
+
return globalThis.EventSource;
|
|
74
|
+
}
|
|
75
|
+
async function throwIfError(response) {
|
|
76
|
+
if (response.ok)
|
|
77
|
+
return;
|
|
78
|
+
let body;
|
|
79
|
+
try {
|
|
80
|
+
body = await response.json();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
body = null;
|
|
84
|
+
}
|
|
85
|
+
throw new PerkamoApiError(response.status, body);
|
|
86
|
+
}
|
|
87
|
+
// ─── Factory ──────────────────────────────────────────────────────────────────
|
|
88
|
+
export function createPerkamoClient(options) {
|
|
89
|
+
const fetcher = requireFetch(options.fetch);
|
|
90
|
+
const baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
91
|
+
function go(input, init) {
|
|
92
|
+
return fetchWithTimeout(fetcher, input, init, options.timeoutMs);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
async emit(userId, event, context = {}, emitOptions = {}) {
|
|
96
|
+
const input = {
|
|
97
|
+
tenant: options.tenant,
|
|
98
|
+
user_id: userId,
|
|
99
|
+
event,
|
|
100
|
+
transaction_id: emitOptions.txId ?? createTransactionId(),
|
|
101
|
+
context,
|
|
102
|
+
occurred_at: (emitOptions.occurredAt ?? new Date()).toISOString(),
|
|
103
|
+
};
|
|
104
|
+
assertSafeEventInput(input);
|
|
105
|
+
const url = `${baseUrl}/v1/events`;
|
|
106
|
+
const body = JSON.stringify(input);
|
|
107
|
+
const response = await go(url, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: await authorizedHeaders(options, true, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
input: url,
|
|
112
|
+
body,
|
|
113
|
+
}),
|
|
114
|
+
body,
|
|
115
|
+
});
|
|
116
|
+
await throwIfError(response);
|
|
117
|
+
return response.json();
|
|
118
|
+
},
|
|
119
|
+
async batch(events) {
|
|
120
|
+
const fullEvents = events.map((e) => ({
|
|
121
|
+
tenant: e.tenant ?? options.tenant,
|
|
122
|
+
user_id: e.user_id,
|
|
123
|
+
event: e.event,
|
|
124
|
+
transaction_id: e.transaction_id,
|
|
125
|
+
context: e.context,
|
|
126
|
+
occurred_at: e.occurred_at,
|
|
127
|
+
}));
|
|
128
|
+
for (const event of fullEvents)
|
|
129
|
+
assertSafeEventInput(event);
|
|
130
|
+
const url = `${baseUrl}/v1/events:batch`;
|
|
131
|
+
const body = JSON.stringify({ events: fullEvents });
|
|
132
|
+
const response = await go(url, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: await authorizedHeaders(options, true, {
|
|
135
|
+
method: "POST",
|
|
136
|
+
input: url,
|
|
137
|
+
body,
|
|
138
|
+
}),
|
|
139
|
+
body,
|
|
140
|
+
});
|
|
141
|
+
await throwIfError(response);
|
|
142
|
+
return response.json();
|
|
143
|
+
},
|
|
144
|
+
async profile(userId) {
|
|
145
|
+
const response = await go(`${baseUrl}/v1/profile/${encodeURIComponent(userId)}`, {
|
|
146
|
+
headers: await authorizedHeaders(options, false),
|
|
147
|
+
});
|
|
148
|
+
await throwIfError(response);
|
|
149
|
+
return response.json();
|
|
150
|
+
},
|
|
151
|
+
subscribeProfile(userId, streamToken, onProfile, onError) {
|
|
152
|
+
if (!streamToken.trim()) {
|
|
153
|
+
throw new Error("Perkamo profile subscriptions require a short-lived stream token");
|
|
154
|
+
}
|
|
155
|
+
const EventSourceCtor = requireEventSource();
|
|
156
|
+
const url = new URL(`${baseUrl}/v1/profile/${encodeURIComponent(userId)}/stream`);
|
|
157
|
+
url.searchParams.set("tenant", options.tenant);
|
|
158
|
+
url.searchParams.set("token", streamToken);
|
|
159
|
+
const source = new EventSourceCtor(url.toString());
|
|
160
|
+
source.onmessage = (event) => {
|
|
161
|
+
try {
|
|
162
|
+
onProfile(JSON.parse(event.data));
|
|
163
|
+
}
|
|
164
|
+
catch (caught) {
|
|
165
|
+
onError?.(caught instanceof Error
|
|
166
|
+
? caught
|
|
167
|
+
: new Error("Perkamo profile stream message could not be parsed"));
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
source.onerror = (event) => onError?.(event);
|
|
171
|
+
return {
|
|
172
|
+
close() {
|
|
173
|
+
source.close();
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# 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/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Browser, Node.js and React Native compatible Perkamo client.",
|
|
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.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"vitest": "4.1.7"
|
|
40
|
+
}
|
|
41
|
+
}
|