@postact-js/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/README.md +52 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/package.json +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @postact-js/sdk
|
|
2
|
+
|
|
3
|
+
Typed client for the [postact](https://postact.app) API. One POST per action, zero dependencies.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm i @postact-js/sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createClient } from "@postact-js/sdk";
|
|
11
|
+
|
|
12
|
+
// One client per project — create it once, at module scope.
|
|
13
|
+
export const postact = createClient<{
|
|
14
|
+
signup: { plan: string };
|
|
15
|
+
"contact-form": { message: string };
|
|
16
|
+
}>({
|
|
17
|
+
project: "acme", // your project slug
|
|
18
|
+
key: process.env.POSTACT_SK!, // sk_… server key
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// action + payload are checked against the map above
|
|
22
|
+
const jobId = await postact.send("signup", { email: "ada@example.com" }, { plan: "pro" });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Untyped is fine too — `createClient({ … })` accepts any action slug and payload.
|
|
26
|
+
|
|
27
|
+
## Person
|
|
28
|
+
|
|
29
|
+
Every call needs a person with an email **or** at least one identifier:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
await postact.send("signup", {
|
|
33
|
+
email: "ada@example.com", // null clears it, omitted leaves it untouched
|
|
34
|
+
identifiers: { userId: 42 }, // your stable ids — used to merge, never duplicate
|
|
35
|
+
metadata: { plan: "pro" }, // stored on the person
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Browser
|
|
40
|
+
|
|
41
|
+
Use a `pk_…` key and add the origin to the action's allowlist in the dashboard. Never ship an
|
|
42
|
+
`sk_…` key to a browser — it can read and write everything in the project.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const postact = createClient({ project: "acme", key: "pk_live_…" });
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Errors
|
|
49
|
+
|
|
50
|
+
Non-2xx throws a `PostactError` carrying the server's message and `status` (401 bad key, 404
|
|
51
|
+
unknown project/action, 429 rate limited, 400 invalid body). `send` resolves with a **job id** —
|
|
52
|
+
the API is async, so a resolved promise means "queued", not "the action's steps ran".
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type Identifiers = Record<string, string | number>;
|
|
2
|
+
export type Metadata = Record<string, string | number | boolean | null>;
|
|
3
|
+
/** Who the action is about. Needs an email or at least one identifier. */
|
|
4
|
+
export type Person = {
|
|
5
|
+
/** `null` clears the address, omitted leaves it untouched */
|
|
6
|
+
email?: string | null;
|
|
7
|
+
identifiers?: Identifiers;
|
|
8
|
+
metadata?: Metadata;
|
|
9
|
+
};
|
|
10
|
+
/** `{ "signup": { plan: string }, "contact-form": { message: string } }` */
|
|
11
|
+
export type ActionMap = Record<string, Record<string, unknown> | undefined>;
|
|
12
|
+
export type ClientOptions = {
|
|
13
|
+
/** project slug, e.g. `"acme"` */
|
|
14
|
+
project: string;
|
|
15
|
+
/** `sk_…` server key, or `pk_…` from a browser on an allowlisted origin */
|
|
16
|
+
key: string;
|
|
17
|
+
/** default `https://api.postact.app` */
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
/** override for tests / custom agents */
|
|
20
|
+
fetch?: typeof globalThis.fetch;
|
|
21
|
+
};
|
|
22
|
+
export declare class PostactError extends Error {
|
|
23
|
+
readonly status: number;
|
|
24
|
+
constructor(message: string, status: number);
|
|
25
|
+
}
|
|
26
|
+
export declare function createClient<A extends ActionMap = ActionMap>(options: ClientOptions): {
|
|
27
|
+
/**
|
|
28
|
+
* Fire one action. Resolves with the queued job id — the API is async (202 + job),
|
|
29
|
+
* so this returning does not mean the action's steps have run.
|
|
30
|
+
*/
|
|
31
|
+
send<K extends keyof A & string>(action: K, person: Person, payload?: A[K]): Promise<string>;
|
|
32
|
+
};
|
|
33
|
+
export type PostactClient<A extends ActionMap = ActionMap> = ReturnType<typeof createClient<A>>;
|
|
34
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAC1D,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAExE,0EAA0E;AAC1E,MAAM,MAAM,MAAM,GAAG;IACnB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAAC;AAE5E,MAAM,MAAM,aAAa,GAAG;IAC1B,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC,CAAC;AAEF,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,EAAE,OAAO,EAAE,aAAa;IAOhF;;;OAGG;SACQ,CAAC,SAAS,MAAM,CAAC,GAAG,MAAM,UAC3B,CAAC,UACD,MAAM,YACJ,CAAC,CAAC,CAAC,CAAC,GACb,OAAO,CAAC,MAAM,CAAC;EAmBrB;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,IAAI,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Zero-dependency client for the postact one-POST API:
|
|
2
|
+
// POST {baseUrl}/p/<project>/a/<action> { person, payload }
|
|
3
|
+
// Typing comes from a caller-supplied action→payload map — no codegen, no generated schema to
|
|
4
|
+
// drift; the map *is* the contract. Works anywhere `fetch` exists (Node 18+, Bun, browsers, edge).
|
|
5
|
+
export class PostactError extends Error {
|
|
6
|
+
status;
|
|
7
|
+
constructor(message, status) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "PostactError";
|
|
10
|
+
this.status = status;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function createClient(options) {
|
|
14
|
+
const base = (options.baseUrl ?? "https://api.postact.app").replace(/\/+$/, "");
|
|
15
|
+
const project = encodeURIComponent(options.project);
|
|
16
|
+
// bind: an unbound globalThis.fetch throws "Illegal invocation" in browsers
|
|
17
|
+
const call = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
18
|
+
return {
|
|
19
|
+
/**
|
|
20
|
+
* Fire one action. Resolves with the queued job id — the API is async (202 + job),
|
|
21
|
+
* so this returning does not mean the action's steps have run.
|
|
22
|
+
*/
|
|
23
|
+
async send(action, person, payload) {
|
|
24
|
+
// The server enforces this too; checking here saves a round trip for the common typo.
|
|
25
|
+
if (person.email === undefined && !Object.keys(person.identifiers ?? {}).length)
|
|
26
|
+
throw new PostactError("person needs an email or at least one identifier", 400);
|
|
27
|
+
const res = await call(`${base}/p/${project}/a/${encodeURIComponent(action)}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${options.key}` },
|
|
30
|
+
body: JSON.stringify({ person, payload }),
|
|
31
|
+
});
|
|
32
|
+
const body = (await res.json().catch(() => null));
|
|
33
|
+
if (!res.ok || !body?.job)
|
|
34
|
+
throw new PostactError(body?.error ?? `request failed (${res.status})`, res.status);
|
|
35
|
+
return body.job;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@postact-js/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed client for the postact API — one POST per action.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"homepage": "https://postact.app",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.build.json",
|
|
24
|
+
"prepublishOnly": "bun run build",
|
|
25
|
+
"typecheck": "tsc --noEmit"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/bun": "^1.3.14",
|
|
29
|
+
"typescript": "^5"
|
|
30
|
+
}
|
|
31
|
+
}
|