contexta-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 ADDED
@@ -0,0 +1,58 @@
1
+ # contexta-sdk
2
+
3
+ Client SDK for **Contexta** — agentic, non-custodial treasury & payroll on Stellar for LATAM.
4
+
5
+ - **Typed API client** for the Contexta API (treasury, payroll, agent, legal).
6
+ - **Sign In With Stellar** (SEP-53) — wallet-agnostic (Freighter, Stellar Wallets Kit, …).
7
+ - **Legal Context Protocol (LCP)** — re-derive and verify a context's SHA-256 independently.
8
+
9
+ Isomorphic (browser + Node ≥ 18), ESM, zero server dependencies.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm i contexta-sdk
15
+ ```
16
+
17
+ ## Sign in with a Stellar wallet
18
+
19
+ ```ts
20
+ import { ContextaClient, signInWithStellar } from "contexta-sdk";
21
+ import { StellarWalletsKit, Networks, defaultModules } from "@creit.tech/stellar-wallets-kit";
22
+
23
+ const client = new ContextaClient({ baseUrl: "https://contexta-api.fly.dev" });
24
+
25
+ StellarWalletsKit.init({ network: Networks.TESTNET, modules: defaultModules() });
26
+ const { address } = await StellarWalletsKit.authModal();
27
+
28
+ const session = await signInWithStellar({
29
+ client,
30
+ address,
31
+ signMessage: async (msg) => (await StellarWalletsKit.signMessage(msg, { address })).signedMessage,
32
+ });
33
+
34
+ // Authenticated, tenant-scoped client:
35
+ const api = client.withSession(session);
36
+ const treasury = await api.treasury();
37
+ const decisions = await api.decisions();
38
+ ```
39
+
40
+ `signMessage` is any function returning the base64 SEP-53 signature, so the SDK
41
+ works with Freighter directly or any wallet adapter.
42
+
43
+ ## Verify a Legal Context independently
44
+
45
+ ```ts
46
+ import { hashLegalContext, verifyLegalContext } from "contexta-sdk";
47
+
48
+ const doc = await client.wellKnownLegalContext("acme.contexta.app");
49
+ const hash = hashLegalContext(doc); // canonical SHA-256 (hex)
50
+ verifyLegalContext(doc, onChainHashFromEvent); // boolean
51
+ ```
52
+
53
+ The canonicalization is byte-for-byte identical to the Contexta platform, so a
54
+ hash bound into a Soroban event can be re-derived and checked client-side.
55
+
56
+ ## License
57
+
58
+ Apache-2.0
package/dist/auth.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import type { ContextaClient } from "./client.js";
2
+ import type { WalletSession } from "./types.js";
3
+ /**
4
+ * A function that signs a SEP-53 message with a Stellar wallet and returns the
5
+ * base64 signature. Wallet-agnostic — pass an adapter for Freighter, Stellar
6
+ * Wallets Kit, etc. Example (Stellar Wallets Kit):
7
+ *
8
+ * const signMessage = async (msg) =>
9
+ * (await StellarWalletsKit.signMessage(msg, { address })).signedMessage;
10
+ */
11
+ export type SignMessageFn = (message: string) => Promise<string> | string;
12
+ /**
13
+ * Sign In With Stellar (SEP-53): request a challenge, have the wallet sign it,
14
+ * and exchange the signature for a Contexta session JWT.
15
+ */
16
+ export declare function signInWithStellar(opts: {
17
+ client: ContextaClient;
18
+ address: string;
19
+ signMessage: SignMessageFn;
20
+ }): Promise<WalletSession>;
21
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AAE1E;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,aAAa,CAAC;CAC5B,GAAG,OAAO,CAAC,aAAa,CAAC,CAKzB"}
package/dist/auth.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Sign In With Stellar (SEP-53): request a challenge, have the wallet sign it,
3
+ * and exchange the signature for a Contexta session JWT.
4
+ */
5
+ export async function signInWithStellar(opts) {
6
+ const { client, address, signMessage } = opts;
7
+ const { message, hmac } = await client.challenge(address);
8
+ const signedMessage = await signMessage(message);
9
+ return client.verify({ address, message, hmac, signedMessage });
10
+ }
11
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAaA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAIvC;IACC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC9C,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,45 @@
1
+ import type { AgentDecision, LegalContext, LegalState, Obligation, TreasurySnapshot, WalletChallenge, WalletSession } from "./types.js";
2
+ export interface ContextaClientOptions {
3
+ /** Base URL of the Contexta API, e.g. https://contexta-api.fly.dev */
4
+ baseUrl: string;
5
+ /** Session JWT (from wallet sign-in). Required for tenant-scoped endpoints. */
6
+ accessToken?: string;
7
+ /** Tenant id to scope requests to (sent as x-tenant-id). */
8
+ tenantId?: string;
9
+ /** Custom fetch (defaults to global fetch). */
10
+ fetch?: typeof fetch;
11
+ }
12
+ /**
13
+ * Typed client for the Contexta API. Use the unauthenticated handshake
14
+ * (`challenge`/`verify`, or the `signInWithStellar` helper) to obtain a session,
15
+ * then `withSession()` to get an authenticated client for tenant-scoped reads.
16
+ */
17
+ export declare class ContextaClient {
18
+ private readonly baseUrl;
19
+ private readonly accessToken?;
20
+ private readonly tenantId?;
21
+ private readonly fetchImpl;
22
+ constructor(options: ContextaClientOptions);
23
+ /** Return a new client carrying the given session (token + tenant). */
24
+ withSession(session: Pick<WalletSession, "token" | "tenantId">): ContextaClient;
25
+ challenge(address: string): Promise<WalletChallenge>;
26
+ verify(input: {
27
+ address: string;
28
+ message: string;
29
+ hmac: string;
30
+ signedMessage: string;
31
+ }): Promise<WalletSession>;
32
+ treasury(): Promise<TreasurySnapshot>;
33
+ obligations(): Promise<Obligation[]>;
34
+ decisions(): Promise<AgentDecision[]>;
35
+ propose(execute?: boolean): Promise<AgentDecision>;
36
+ legal(): Promise<LegalState>;
37
+ /** Fetch a tenant's public legal-context.json (served at the API mirror). */
38
+ wellKnownLegalContext(domain: string): Promise<LegalContext>;
39
+ private request;
40
+ }
41
+ export declare class ContextaApiError extends Error {
42
+ readonly status: number;
43
+ constructor(status: number, message: string);
44
+ }
45
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,OAAO,EAAE,qBAAqB;IAS1C,uEAAuE;IACvE,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,GAAG,UAAU,CAAC,GAAG,cAAc;IAU/E,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAIpD,MAAM,CAAC,KAAK,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,aAAa,CAAC;IAK1B,QAAQ,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAIrC,WAAW,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAIpC,SAAS,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAIrC,OAAO,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;IAIhD,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC;IAI5B,6EAA6E;IACvE,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;YASpD,OAAO;CA6BtB;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAC9B,OAAO,EAAE,MAAM;CAKlB"}
package/dist/client.js ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Typed client for the Contexta API. Use the unauthenticated handshake
3
+ * (`challenge`/`verify`, or the `signInWithStellar` helper) to obtain a session,
4
+ * then `withSession()` to get an authenticated client for tenant-scoped reads.
5
+ */
6
+ export class ContextaClient {
7
+ baseUrl;
8
+ accessToken;
9
+ tenantId;
10
+ fetchImpl;
11
+ constructor(options) {
12
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
13
+ this.accessToken = options.accessToken;
14
+ this.tenantId = options.tenantId;
15
+ const f = options.fetch ?? globalThis.fetch;
16
+ if (!f)
17
+ throw new Error("No fetch implementation available; pass options.fetch");
18
+ this.fetchImpl = f;
19
+ }
20
+ /** Return a new client carrying the given session (token + tenant). */
21
+ withSession(session) {
22
+ return new ContextaClient({
23
+ baseUrl: this.baseUrl,
24
+ accessToken: session.token,
25
+ tenantId: session.tenantId,
26
+ fetch: this.fetchImpl,
27
+ });
28
+ }
29
+ // ── Wallet sign-in handshake (no auth) ───────────────────────────────────
30
+ challenge(address) {
31
+ return this.request("/auth/wallet/challenge", { method: "POST", body: { address } }, false);
32
+ }
33
+ verify(input) {
34
+ return this.request("/auth/wallet/verify", { method: "POST", body: input }, false);
35
+ }
36
+ // ── Tenant-scoped reads (require a session) ──────────────────────────────
37
+ treasury() {
38
+ return this.request("/treasury");
39
+ }
40
+ obligations() {
41
+ return this.request("/payroll/obligations");
42
+ }
43
+ decisions() {
44
+ return this.request("/agent/decisions");
45
+ }
46
+ propose(execute = false) {
47
+ return this.request("/agent/propose", { method: "POST", body: { execute } });
48
+ }
49
+ legal() {
50
+ return this.request("/legal");
51
+ }
52
+ /** Fetch a tenant's public legal-context.json (served at the API mirror). */
53
+ async wellKnownLegalContext(domain) {
54
+ const res = await this.fetchImpl(`${this.baseUrl}/.well-known/legal-context.json?domain=${encodeURIComponent(domain)}`, { headers: { accept: "application/json" } });
55
+ if (!res.ok)
56
+ throw new ContextaApiError(res.status, `.well-known -> ${res.status}`);
57
+ return (await res.json());
58
+ }
59
+ async request(path, init = {}, auth = true) {
60
+ const headers = { "content-type": "application/json" };
61
+ if (auth) {
62
+ if (!this.accessToken || !this.tenantId) {
63
+ throw new Error(`Endpoint ${path} requires a session — call withSession() first`);
64
+ }
65
+ headers.authorization = `Bearer ${this.accessToken}`;
66
+ headers["x-tenant-id"] = this.tenantId;
67
+ }
68
+ const res = await this.fetchImpl(`${this.baseUrl}/api/v1${path}`, {
69
+ method: init.method ?? "GET",
70
+ headers,
71
+ body: init.body !== undefined ? JSON.stringify(init.body) : undefined,
72
+ });
73
+ const text = await res.text();
74
+ const json = text ? JSON.parse(text) : null;
75
+ if (!res.ok) {
76
+ let msg = `API ${path} -> ${res.status}`;
77
+ if (json && typeof json === "object" && "error" in json) {
78
+ msg = String(json.error);
79
+ }
80
+ throw new ContextaApiError(res.status, msg);
81
+ }
82
+ return json;
83
+ }
84
+ }
85
+ export class ContextaApiError extends Error {
86
+ status;
87
+ constructor(status, message) {
88
+ super(message);
89
+ this.status = status;
90
+ this.name = "ContextaApiError";
91
+ }
92
+ }
93
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { ContextaClient, ContextaApiError, type ContextaClientOptions } from "./client.js";
2
+ export { signInWithStellar, type SignMessageFn } from "./auth.js";
3
+ export { canonicalize, hashLegalContext, verifyLegalContext, legalContextUrl, LCP_WELL_KNOWN_PATH, } from "./lcp.js";
4
+ export * from "./types.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAClB,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { ContextaClient, ContextaApiError } from "./client.js";
2
+ export { signInWithStellar } from "./auth.js";
3
+ export { canonicalize, hashLegalContext, verifyLegalContext, legalContextUrl, LCP_WELL_KNOWN_PATH, } from "./lcp.js";
4
+ export * from "./types.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAA8B,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,iBAAiB,EAAsB,MAAM,WAAW,CAAC;AAClE,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAClB,cAAc,YAAY,CAAC"}
package/dist/lcp.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { LegalContext } from "./types.js";
2
+ /**
3
+ * Deterministic JSON canonicalization (subset of RFC 8785 / JCS): object keys
4
+ * sorted, no insignificant whitespace, arrays preserved in order, `undefined`
5
+ * dropped. Byte-for-byte identical to the Contexta platform so an SDK consumer
6
+ * can independently re-derive and verify a legal context's SHA-256.
7
+ */
8
+ export declare function canonicalize(value: unknown): string;
9
+ /** SHA-256 (hex) of a legal context over its canonical JSON form. */
10
+ export declare function hashLegalContext(context: LegalContext): string;
11
+ /**
12
+ * Verify a legal context document against an expected hash (e.g. one bound into
13
+ * an on-chain event or returned by the API). Case-insensitive hex compare.
14
+ */
15
+ export declare function verifyLegalContext(context: LegalContext, expectedHash: string): boolean;
16
+ export declare const LCP_WELL_KNOWN_PATH = "/.well-known/legal-context.json";
17
+ export declare function legalContextUrl(tenantDomain: string): string;
18
+ //# sourceMappingURL=lcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.d.ts","sourceRoot":"","sources":["../src/lcp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAmBnD;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAE9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED,eAAO,MAAM,mBAAmB,oCAAoC,CAAC;AAErE,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE5D"}
package/dist/lcp.js ADDED
@@ -0,0 +1,46 @@
1
+ import { sha256 } from "@noble/hashes/sha256";
2
+ import { bytesToHex, utf8ToBytes } from "@noble/hashes/utils";
3
+ /**
4
+ * Deterministic JSON canonicalization (subset of RFC 8785 / JCS): object keys
5
+ * sorted, no insignificant whitespace, arrays preserved in order, `undefined`
6
+ * dropped. Byte-for-byte identical to the Contexta platform so an SDK consumer
7
+ * can independently re-derive and verify a legal context's SHA-256.
8
+ */
9
+ export function canonicalize(value) {
10
+ if (value === null)
11
+ return "null";
12
+ if (typeof value === "number") {
13
+ if (!Number.isFinite(value))
14
+ throw new Error("Cannot canonicalize non-finite number");
15
+ return JSON.stringify(value);
16
+ }
17
+ if (typeof value === "boolean" || typeof value === "string") {
18
+ return JSON.stringify(value);
19
+ }
20
+ if (Array.isArray(value)) {
21
+ return `[${value.map(canonicalize).join(",")}]`;
22
+ }
23
+ if (typeof value === "object") {
24
+ const entries = Object.entries(value)
25
+ .filter(([, v]) => v !== undefined)
26
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
27
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalize(v)}`).join(",")}}`;
28
+ }
29
+ throw new Error(`Cannot canonicalize value of type ${typeof value}`);
30
+ }
31
+ /** SHA-256 (hex) of a legal context over its canonical JSON form. */
32
+ export function hashLegalContext(context) {
33
+ return bytesToHex(sha256(utf8ToBytes(canonicalize(context))));
34
+ }
35
+ /**
36
+ * Verify a legal context document against an expected hash (e.g. one bound into
37
+ * an on-chain event or returned by the API). Case-insensitive hex compare.
38
+ */
39
+ export function verifyLegalContext(context, expectedHash) {
40
+ return hashLegalContext(context).toLowerCase() === expectedHash.toLowerCase();
41
+ }
42
+ export const LCP_WELL_KNOWN_PATH = "/.well-known/legal-context.json";
43
+ export function legalContextUrl(tenantDomain) {
44
+ return `https://${tenantDomain}${LCP_WELL_KNOWN_PATH}`;
45
+ }
46
+ //# sourceMappingURL=lcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lcp.js","sourceRoot":"","sources":["../src/lcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAG9D;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACtF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC5D,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAClD,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;aAC7D,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC;aAClC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC7F,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,qCAAqC,OAAO,KAAK,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,gBAAgB,CAAC,OAAqB;IACpD,OAAO,UAAU,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAqB,EAAE,YAAoB;IAC5E,OAAO,gBAAgB,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAAC;AAChF,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,iCAAiC,CAAC;AAErE,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,OAAO,WAAW,YAAY,GAAG,mBAAmB,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,110 @@
1
+ /** Public types for the Contexta SDK. Mirror the API's JSON response shapes. */
2
+ export type Country = "BR" | "AR" | "CO";
3
+ export type Asset = "USDC" | "XLM" | "CETES" | "BRL" | "ARS" | "COP";
4
+ export type Strategy = "liquidity" | "defindex_vault" | "blend_pool";
5
+ export type Rail = "PIX" | "TRANSFERENCIAS_3" | "BRE_B" | "STELLAR" | "SEP24" | "SEP31";
6
+ export interface TreasuryConfig {
7
+ minLiquidityBaseUnits: string;
8
+ maxYieldBps: number;
9
+ volatilitySensitivity: number;
10
+ countryLimitsBps: Record<string, number>;
11
+ }
12
+ export interface TreasuryPosition {
13
+ asset: string;
14
+ strategy: Strategy;
15
+ strategyRef: string | null;
16
+ amountBaseUnits: string;
17
+ apyBps: number | null;
18
+ }
19
+ export interface TreasurySnapshot {
20
+ config: TreasuryConfig | null;
21
+ positions: TreasuryPosition[];
22
+ totals: {
23
+ liquidBaseUnits: string;
24
+ yieldBaseUnits: string;
25
+ totalBaseUnits: string;
26
+ yieldShareBps: number;
27
+ };
28
+ }
29
+ export interface Obligation {
30
+ scheduleId: string;
31
+ scheduleName: string;
32
+ nextRunAt: string;
33
+ asset: string;
34
+ requiredBaseUnits: string;
35
+ employeeCount?: number;
36
+ }
37
+ export interface AgentDecision {
38
+ id: string;
39
+ action: string;
40
+ rationale: string;
41
+ status: string;
42
+ legalContextHash: string | null;
43
+ stellarTxHash: string | null;
44
+ createdAt: string;
45
+ }
46
+ export interface LegalState {
47
+ published: boolean;
48
+ hash?: string;
49
+ document?: LegalContext;
50
+ }
51
+ export interface WalletChallenge {
52
+ message: string;
53
+ hmac: string;
54
+ }
55
+ export interface WalletSession {
56
+ token: string;
57
+ tokenType: "Bearer";
58
+ expiresAt: string;
59
+ address: string;
60
+ userId: string;
61
+ tenantId: string;
62
+ role: string;
63
+ }
64
+ export interface LcpParty {
65
+ legalName: string;
66
+ jurisdiction: string;
67
+ registrationId?: string;
68
+ contactEmail: string;
69
+ }
70
+ export interface LcpConsentRequirement {
71
+ id: string;
72
+ description: string;
73
+ required: boolean;
74
+ scope: Array<"treasury" | "payroll" | "yield" | "onramp" | "offramp">;
75
+ }
76
+ export interface LcpDisputeChannel {
77
+ type: "arbitration" | "mediation" | "court" | "ombudsman";
78
+ provider: string;
79
+ venue: string;
80
+ governingLaw: string;
81
+ language: string;
82
+ }
83
+ export interface LegalContext {
84
+ specVersion: string;
85
+ contextId: string;
86
+ version: number;
87
+ tenantDomain: string;
88
+ provider: LcpParty;
89
+ terms: {
90
+ url: string;
91
+ sha256: string;
92
+ effectiveDate: string;
93
+ };
94
+ jurisdiction: string;
95
+ consentRequirements: LcpConsentRequirement[];
96
+ disputeChannels: LcpDisputeChannel[];
97
+ settlement: {
98
+ networks: string[];
99
+ assets: string[];
100
+ };
101
+ publishedAt: string;
102
+ }
103
+ /** Compact binding embedded into agentic Stellar transactions. */
104
+ export interface LcpBinding {
105
+ contextId: string;
106
+ version: number;
107
+ hash: string;
108
+ consents: string[];
109
+ }
110
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AACzC,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AACrE,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,gBAAgB,GAAG,YAAY,CAAC;AACrE,MAAM,MAAM,IAAI,GAAG,KAAK,GAAG,kBAAkB,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAExF,MAAM,WAAW,cAAc;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,MAAM,EAAE;QACN,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAGD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,QAAQ,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,qBAAqB,EAAE,CAAC;IAC7C,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,kEAAkE;AAClE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ /** Public types for the Contexta SDK. Mirror the API's JSON response shapes. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gFAAgF"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "contexta-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Client SDK for Contexta — agentic treasury & payroll on Stellar. Typed API client, Stellar wallet sign-in (SEP-53), and Legal Context Protocol (LCP) hashing/verification.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "sideEffects": false,
21
+ "keywords": [
22
+ "stellar",
23
+ "soroban",
24
+ "contexta",
25
+ "sdk",
26
+ "treasury",
27
+ "payroll",
28
+ "lcp",
29
+ "legal-context-protocol",
30
+ "freighter",
31
+ "sep-53",
32
+ "wallet-auth"
33
+ ],
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/contexta/contexta",
37
+ "directory": "packages/sdk"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "engines": {
43
+ "node": ">=18"
44
+ },
45
+ "dependencies": {
46
+ "@noble/hashes": "^1.6.1"
47
+ },
48
+ "devDependencies": {
49
+ "typescript": "^5.7.3",
50
+ "vitest": "^2.1.8"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -p tsconfig.json",
54
+ "typecheck": "tsc -p tsconfig.json --noEmit",
55
+ "lint": "eslint \"src/**/*.ts\"",
56
+ "test": "vitest run"
57
+ }
58
+ }