@sente-labs/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/dist/index.cjs ADDED
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Sente: () => Sente,
24
+ SenteError: () => SenteError
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var SenteError = class extends Error {
28
+ constructor(status, message, body) {
29
+ super(message);
30
+ this.status = status;
31
+ this.body = body;
32
+ this.name = "SenteError";
33
+ }
34
+ status;
35
+ body;
36
+ };
37
+ function qs(o) {
38
+ const p = new URLSearchParams();
39
+ for (const [k, v] of Object.entries(o)) if (v !== void 0 && v !== null) p.set(k, String(v));
40
+ const s = p.toString();
41
+ return s ? `?${s}` : "";
42
+ }
43
+ var Sente = class {
44
+ #apiKey;
45
+ #baseUrl;
46
+ #fetch;
47
+ constructor(opts) {
48
+ this.#apiKey = opts.apiKey;
49
+ this.#baseUrl = opts.baseUrl ?? "https://api.sente.run";
50
+ this.#fetch = opts.fetch ?? ((url, init) => fetch(url, init));
51
+ }
52
+ async #req(method, path, body) {
53
+ const res = await this.#fetch(`${this.#baseUrl}${path}`, {
54
+ method,
55
+ headers: { authorization: `Bearer ${this.#apiKey}`, "content-type": "application/json" },
56
+ body: body === void 0 ? void 0 : JSON.stringify(body)
57
+ });
58
+ if (!res.ok) {
59
+ throw new SenteError(res.status, `${method} ${path} \u2192 ${res.status}`, await res.text().catch(() => null));
60
+ }
61
+ if (res.status === 204) return void 0;
62
+ return await res.json();
63
+ }
64
+ identities = {
65
+ create: (input = {}) => this.#req("POST", "/v1/identities", input),
66
+ get: (id) => this.#req("GET", `/v1/identities/${id}`),
67
+ list: () => this.#req("GET", "/v1/identities")
68
+ };
69
+ messages = {
70
+ list: (identityId, opts = {}) => this.#req("GET", `/v1/messages${qs({ identityId, ...opts })}`),
71
+ get: (id) => this.#req("GET", `/v1/messages/${id}`),
72
+ /** Long-poll for the next matching message; resolves to null on timeout. */
73
+ waitFor: async (identityId, opts = {}) => await this.#req("GET", `/v1/messages/wait${qs({ identityId, ...opts })}`) ?? null,
74
+ /**
75
+ * Continuously yield messages as they arrive (client-side long-poll loop). Break out of the
76
+ * `for await` to stop. For production, prefer webhooks (push) over this (poll).
77
+ */
78
+ stream: (identityId, opts = {}) => {
79
+ const messages = this.messages;
80
+ return (async function* () {
81
+ let since = opts.since;
82
+ for (; ; ) {
83
+ const msg = await messages.waitFor(identityId, { since, timeout: opts.timeout ?? 25 });
84
+ if (msg) {
85
+ yield msg;
86
+ since = msg.createdAt;
87
+ }
88
+ }
89
+ })();
90
+ }
91
+ };
92
+ webhooks = {
93
+ /** Register YOUR endpoint with Sente so it delivers events there (you build/host the endpoint). */
94
+ register: (input) => this.#req("POST", "/v1/webhooks", input),
95
+ list: () => this.#req("GET", "/v1/webhooks"),
96
+ delete: (id) => this.#req("DELETE", `/v1/webhooks/${id}`)
97
+ };
98
+ };
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ Sente,
102
+ SenteError
103
+ });
@@ -0,0 +1,81 @@
1
+ export type Identity = {
2
+ id: string;
3
+ name: string | null;
4
+ description?: string | null;
5
+ email: string;
6
+ createdAt?: string;
7
+ };
8
+ export type Message = {
9
+ id: string;
10
+ identityId: string;
11
+ direction: "inbound" | "outbound";
12
+ fromAddr: string;
13
+ toAddr: string;
14
+ subject: string | null;
15
+ parsed?: unknown;
16
+ annotation?: unknown;
17
+ createdAt: string;
18
+ };
19
+ export type Webhook = {
20
+ id: string;
21
+ url: string;
22
+ events: string[];
23
+ identityId: string | null;
24
+ createdAt?: string;
25
+ };
26
+ export type SenteOptions = {
27
+ apiKey: string;
28
+ baseUrl?: string;
29
+ /** Override the fetch implementation (handy for tests). */
30
+ fetch?: (url: string, init?: RequestInit) => Promise<Response>;
31
+ };
32
+ export declare class SenteError extends Error {
33
+ readonly status: number;
34
+ readonly body: unknown;
35
+ constructor(status: number, message: string, body: unknown);
36
+ }
37
+ export declare class Sente {
38
+ #private;
39
+ constructor(opts: SenteOptions);
40
+ identities: {
41
+ create: (input?: {
42
+ name?: string;
43
+ description?: string;
44
+ }) => Promise<Identity>;
45
+ get: (id: string) => Promise<Identity>;
46
+ list: () => Promise<Identity[]>;
47
+ };
48
+ messages: {
49
+ list: (identityId: string, opts?: {
50
+ since?: string;
51
+ direction?: "inbound" | "outbound";
52
+ limit?: number;
53
+ }) => Promise<Message[]>;
54
+ get: (id: string) => Promise<Message>;
55
+ /** Long-poll for the next matching message; resolves to null on timeout. */
56
+ waitFor: (identityId: string, opts?: {
57
+ since?: string;
58
+ timeout?: number;
59
+ }) => Promise<Message | null>;
60
+ /**
61
+ * Continuously yield messages as they arrive (client-side long-poll loop). Break out of the
62
+ * `for await` to stop. For production, prefer webhooks (push) over this (poll).
63
+ */
64
+ stream: (identityId: string, opts?: {
65
+ since?: string;
66
+ timeout?: number;
67
+ }) => AsyncGenerator<Message>;
68
+ };
69
+ webhooks: {
70
+ /** Register YOUR endpoint with Sente so it delivers events there (you build/host the endpoint). */
71
+ register: (input: {
72
+ url: string;
73
+ events: string[];
74
+ identityId?: string;
75
+ }) => Promise<Webhook & {
76
+ secret: string;
77
+ }>;
78
+ list: () => Promise<Webhook[]>;
79
+ delete: (id: string) => Promise<void>;
80
+ };
81
+ }
package/dist/index.js ADDED
@@ -0,0 +1,77 @@
1
+ // src/index.ts
2
+ var SenteError = class extends Error {
3
+ constructor(status, message, body) {
4
+ super(message);
5
+ this.status = status;
6
+ this.body = body;
7
+ this.name = "SenteError";
8
+ }
9
+ status;
10
+ body;
11
+ };
12
+ function qs(o) {
13
+ const p = new URLSearchParams();
14
+ for (const [k, v] of Object.entries(o)) if (v !== void 0 && v !== null) p.set(k, String(v));
15
+ const s = p.toString();
16
+ return s ? `?${s}` : "";
17
+ }
18
+ var Sente = class {
19
+ #apiKey;
20
+ #baseUrl;
21
+ #fetch;
22
+ constructor(opts) {
23
+ this.#apiKey = opts.apiKey;
24
+ this.#baseUrl = opts.baseUrl ?? "https://api.sente.run";
25
+ this.#fetch = opts.fetch ?? ((url, init) => fetch(url, init));
26
+ }
27
+ async #req(method, path, body) {
28
+ const res = await this.#fetch(`${this.#baseUrl}${path}`, {
29
+ method,
30
+ headers: { authorization: `Bearer ${this.#apiKey}`, "content-type": "application/json" },
31
+ body: body === void 0 ? void 0 : JSON.stringify(body)
32
+ });
33
+ if (!res.ok) {
34
+ throw new SenteError(res.status, `${method} ${path} \u2192 ${res.status}`, await res.text().catch(() => null));
35
+ }
36
+ if (res.status === 204) return void 0;
37
+ return await res.json();
38
+ }
39
+ identities = {
40
+ create: (input = {}) => this.#req("POST", "/v1/identities", input),
41
+ get: (id) => this.#req("GET", `/v1/identities/${id}`),
42
+ list: () => this.#req("GET", "/v1/identities")
43
+ };
44
+ messages = {
45
+ list: (identityId, opts = {}) => this.#req("GET", `/v1/messages${qs({ identityId, ...opts })}`),
46
+ get: (id) => this.#req("GET", `/v1/messages/${id}`),
47
+ /** Long-poll for the next matching message; resolves to null on timeout. */
48
+ waitFor: async (identityId, opts = {}) => await this.#req("GET", `/v1/messages/wait${qs({ identityId, ...opts })}`) ?? null,
49
+ /**
50
+ * Continuously yield messages as they arrive (client-side long-poll loop). Break out of the
51
+ * `for await` to stop. For production, prefer webhooks (push) over this (poll).
52
+ */
53
+ stream: (identityId, opts = {}) => {
54
+ const messages = this.messages;
55
+ return (async function* () {
56
+ let since = opts.since;
57
+ for (; ; ) {
58
+ const msg = await messages.waitFor(identityId, { since, timeout: opts.timeout ?? 25 });
59
+ if (msg) {
60
+ yield msg;
61
+ since = msg.createdAt;
62
+ }
63
+ }
64
+ })();
65
+ }
66
+ };
67
+ webhooks = {
68
+ /** Register YOUR endpoint with Sente so it delivers events there (you build/host the endpoint). */
69
+ register: (input) => this.#req("POST", "/v1/webhooks", input),
70
+ list: () => this.#req("GET", "/v1/webhooks"),
71
+ delete: (id) => this.#req("DELETE", `/v1/webhooks/${id}`)
72
+ };
73
+ };
74
+ export {
75
+ Sente,
76
+ SenteError
77
+ };
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@sente-labs/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Typed client for the Sente API — managed email identities for AI agents.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.cjs"
12
+ }
13
+ },
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/shim2k/sente-labs.git",
26
+ "directory": "sente/packages/sdk"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^26.0.1",
30
+ "tsup": "^8.0.0",
31
+ "typescript": "^6.0.3",
32
+ "vitest": "^4.1.9",
33
+ "app": "0.0.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsup src/index.ts --format esm,cjs --clean && tsc -p tsconfig.build.json",
37
+ "test": "vitest run",
38
+ "typecheck": "tsc --noEmit"
39
+ }
40
+ }