@provenonce/partner 1.1.0 → 1.2.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.d.mts CHANGED
@@ -38,8 +38,18 @@ interface SigilCheckValid {
38
38
  interface SigilCheckInvalid {
39
39
  valid: false;
40
40
  reason: 'no_sigil' | 'inactive' | 'not_registered';
41
- /** Pre-built signup URL with your ref token embedded. Redirect the user here. */
41
+ /**
42
+ * Pre-built signup URL with your ref token AND attribution token embedded.
43
+ * Redirect the user here — attribution is preserved however long they take to register.
44
+ * Format: provenonce.io/register?ref={ref_token}&at={pvr_token}
45
+ */
42
46
  signupUrl: string | null;
47
+ /**
48
+ * Signed attribution token (pvr_...). Already embedded in signupUrl.
49
+ * Also pass this as `at` in POST /api/v1/sigil if you handle the
50
+ * purchase flow directly (e.g. agent-autonomous payment path).
51
+ */
52
+ attributionToken: string | null;
43
53
  }
44
54
  type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;
45
55
  /**
package/dist/index.d.ts CHANGED
@@ -38,8 +38,18 @@ interface SigilCheckValid {
38
38
  interface SigilCheckInvalid {
39
39
  valid: false;
40
40
  reason: 'no_sigil' | 'inactive' | 'not_registered';
41
- /** Pre-built signup URL with your ref token embedded. Redirect the user here. */
41
+ /**
42
+ * Pre-built signup URL with your ref token AND attribution token embedded.
43
+ * Redirect the user here — attribution is preserved however long they take to register.
44
+ * Format: provenonce.io/register?ref={ref_token}&at={pvr_token}
45
+ */
42
46
  signupUrl: string | null;
47
+ /**
48
+ * Signed attribution token (pvr_...). Already embedded in signupUrl.
49
+ * Also pass this as `at` in POST /api/v1/sigil if you handle the
50
+ * purchase flow directly (e.g. agent-autonomous payment path).
51
+ */
52
+ attributionToken: string | null;
43
53
  }
44
54
  type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;
45
55
  /**
package/dist/index.js CHANGED
@@ -76,7 +76,8 @@ async function checkSigil(opts) {
76
76
  return {
77
77
  valid: false,
78
78
  reason: data.reason ?? "no_sigil",
79
- signupUrl: data.signup_url ?? null
79
+ signupUrl: data.signup_url ?? null,
80
+ attributionToken: data.attribution_token ?? null
80
81
  };
81
82
  }
82
83
  async function createPartnerSession(opts) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @provenonce/partner — Provenonce Partner SDK\r\n *\r\n * For skill developers. Wraps GET /api/v1/sigil/check so any skill can verify\r\n * an agent's SIGIL and get a signup URL in one call.\r\n *\r\n * Usage (server-side only — partner key must never be in a client bundle):\r\n *\r\n * import { checkSigil } from '@provenonce/partner'\r\n *\r\n * const result = await checkSigil({\r\n * agentHash: '0x1234...',\r\n * partnerKey: process.env.PROVENONCE_PARTNER_KEY!,\r\n * })\r\n *\r\n * if (!result.valid) {\r\n * return redirect(result.signupUrl)\r\n * }\r\n */\r\n\r\nconst DEFAULT_BASE_URL = 'https://provenonce.io';\r\nconst DEFAULT_TIMEOUT_MS = 5_000;\r\n\r\n// ── Types ─────────────────────────────────────────────────────────────────────\r\n\r\nexport interface SigilCheckOptions {\r\n /** Agent hash to check (0x-prefixed 64-char hex) */\r\n agentHash: string;\r\n /** Your pvp_ partner key — server-side only, never expose to clients */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\n/** Agent has a valid SIGIL */\r\nexport interface SigilCheckValid {\r\n valid: true;\r\n sigil: string;\r\n identityClass: string;\r\n tier: string;\r\n}\r\n\r\n/** Agent has no SIGIL (or is inactive) — signupUrl is pre-built with your ref token */\r\nexport interface SigilCheckInvalid {\r\n valid: false;\r\n reason: 'no_sigil' | 'inactive' | 'not_registered';\r\n /** Pre-built signup URL with your ref token embedded. Redirect the user here. */\r\n signupUrl: string | null;\r\n}\r\n\r\nexport type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;\r\n\r\n// ── Main function ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether an agent has a valid SIGIL.\r\n *\r\n * Server-side only. The `partnerKey` (pvp_...) must never be sent to clients.\r\n *\r\n * On success: returns { valid: true, sigil, identityClass, tier }\r\n * On no SIGIL: returns { valid: false, reason, signupUrl } — redirect to signupUrl\r\n * On auth error: throws ProvenoncePartnerError with status 401/403\r\n * On rate limit: throws ProvenoncePartnerError with status 429\r\n */\r\nexport async function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult> {\r\n const { agentHash, partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!agentHash) throw new ProvenoncePartnerError('agentHash is required', 400);\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/sigil/check?hash=${encodeURIComponent(agentHash)}`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError(\r\n (body as any)?.error ?? 'Partner key rejected',\r\n res.status,\r\n );\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n\r\n if (data.valid === true) {\r\n return {\r\n valid: true,\r\n sigil: data.sigil ?? '',\r\n identityClass: data.identity_class ?? '',\r\n tier: data.tier ?? '',\r\n };\r\n }\r\n\r\n return {\r\n valid: false,\r\n reason: data.reason ?? 'no_sigil',\r\n signupUrl: data.signup_url ?? null,\r\n };\r\n}\r\n\r\n// ── Partner Session Token (D-84) ──────────────────────────────────────────────\r\n\r\nexport interface PartnerSessionOptions {\r\n /** Your pvp_ partner master key */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface PartnerSession {\r\n /** Short-lived pvt_ token — use this for all subsequent API calls */\r\n token: string;\r\n /** ISO 8601 expiry timestamp */\r\n expiresAt: string;\r\n /** Seconds until expiry (nominally 3600) */\r\n expiresInSeconds: number;\r\n}\r\n\r\n/**\r\n * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.\r\n *\r\n * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token\r\n * for all subsequent checkSigil() and other partner API calls.\r\n *\r\n * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment\r\n * (e.g. on server startup or in middleware) and reuse until near expiry.\r\n *\r\n * @example\r\n * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })\r\n * const result = await checkSigil({ agentHash, partnerKey: session.token })\r\n */\r\nexport async function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession> {\r\n const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/partner/token`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n method: 'POST',\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError((body as any)?.error ?? 'Partner key rejected', res.status);\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n return {\r\n token: data.token,\r\n expiresAt: data.expires_at,\r\n expiresInSeconds: data.expires_in_seconds,\r\n };\r\n}\r\n\r\n// ── Error class ───────────────────────────────────────────────────────────────\r\n\r\nexport class ProvenoncePartnerError extends Error {\r\n readonly status: number;\r\n\r\n constructor(message: string, status: number) {\r\n super(message);\r\n this.name = 'ProvenoncePartnerError';\r\n this.status = status;\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @provenonce/partner — Provenonce Partner SDK\r\n *\r\n * For skill developers. Wraps GET /api/v1/sigil/check so any skill can verify\r\n * an agent's SIGIL and get a signup URL in one call.\r\n *\r\n * Usage (server-side only — partner key must never be in a client bundle):\r\n *\r\n * import { checkSigil } from '@provenonce/partner'\r\n *\r\n * const result = await checkSigil({\r\n * agentHash: '0x1234...',\r\n * partnerKey: process.env.PROVENONCE_PARTNER_KEY!,\r\n * })\r\n *\r\n * if (!result.valid) {\r\n * return redirect(result.signupUrl)\r\n * }\r\n */\r\n\r\nconst DEFAULT_BASE_URL = 'https://provenonce.io';\r\nconst DEFAULT_TIMEOUT_MS = 5_000;\r\n\r\n// ── Types ─────────────────────────────────────────────────────────────────────\r\n\r\nexport interface SigilCheckOptions {\r\n /** Agent hash to check (0x-prefixed 64-char hex) */\r\n agentHash: string;\r\n /** Your pvp_ partner key — server-side only, never expose to clients */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\n/** Agent has a valid SIGIL */\r\nexport interface SigilCheckValid {\r\n valid: true;\r\n sigil: string;\r\n identityClass: string;\r\n tier: string;\r\n}\r\n\r\n/** Agent has no SIGIL (or is inactive) — signupUrl is pre-built with your ref token */\r\nexport interface SigilCheckInvalid {\r\n valid: false;\r\n reason: 'no_sigil' | 'inactive' | 'not_registered';\r\n /**\r\n * Pre-built signup URL with your ref token AND attribution token embedded.\r\n * Redirect the user here — attribution is preserved however long they take to register.\r\n * Format: provenonce.io/register?ref={ref_token}&at={pvr_token}\r\n */\r\n signupUrl: string | null;\r\n /**\r\n * Signed attribution token (pvr_...). Already embedded in signupUrl.\r\n * Also pass this as `at` in POST /api/v1/sigil if you handle the\r\n * purchase flow directly (e.g. agent-autonomous payment path).\r\n */\r\n attributionToken: string | null;\r\n}\r\n\r\nexport type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;\r\n\r\n// ── Main function ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether an agent has a valid SIGIL.\r\n *\r\n * Server-side only. The `partnerKey` (pvp_...) must never be sent to clients.\r\n *\r\n * On success: returns { valid: true, sigil, identityClass, tier }\r\n * On no SIGIL: returns { valid: false, reason, signupUrl } — redirect to signupUrl\r\n * On auth error: throws ProvenoncePartnerError with status 401/403\r\n * On rate limit: throws ProvenoncePartnerError with status 429\r\n */\r\nexport async function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult> {\r\n const { agentHash, partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!agentHash) throw new ProvenoncePartnerError('agentHash is required', 400);\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/sigil/check?hash=${encodeURIComponent(agentHash)}`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError(\r\n (body as any)?.error ?? 'Partner key rejected',\r\n res.status,\r\n );\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n\r\n if (data.valid === true) {\r\n return {\r\n valid: true,\r\n sigil: data.sigil ?? '',\r\n identityClass: data.identity_class ?? '',\r\n tier: data.tier ?? '',\r\n };\r\n }\r\n\r\n return {\r\n valid: false,\r\n reason: data.reason ?? 'no_sigil',\r\n signupUrl: data.signup_url ?? null,\r\n attributionToken: data.attribution_token ?? null,\r\n };\r\n}\r\n\r\n// ── Partner Session Token (D-84) ──────────────────────────────────────────────\r\n\r\nexport interface PartnerSessionOptions {\r\n /** Your pvp_ partner master key */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface PartnerSession {\r\n /** Short-lived pvt_ token — use this for all subsequent API calls */\r\n token: string;\r\n /** ISO 8601 expiry timestamp */\r\n expiresAt: string;\r\n /** Seconds until expiry (nominally 3600) */\r\n expiresInSeconds: number;\r\n}\r\n\r\n/**\r\n * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.\r\n *\r\n * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token\r\n * for all subsequent checkSigil() and other partner API calls.\r\n *\r\n * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment\r\n * (e.g. on server startup or in middleware) and reuse until near expiry.\r\n *\r\n * @example\r\n * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })\r\n * const result = await checkSigil({ agentHash, partnerKey: session.token })\r\n */\r\nexport async function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession> {\r\n const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/partner/token`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n method: 'POST',\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError((body as any)?.error ?? 'Partner key rejected', res.status);\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n return {\r\n token: data.token,\r\n expiresAt: data.expires_at,\r\n expiresInSeconds: data.expires_in_seconds,\r\n };\r\n}\r\n\r\n// ── Error class ───────────────────────────────────────────────────────────────\r\n\r\nexport class ProvenoncePartnerError extends Error {\r\n readonly status: number;\r\n\r\n constructor(message: string, status: number) {\r\n super(message);\r\n this.name = 'ProvenoncePartnerError';\r\n this.status = status;\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -50,7 +50,8 @@ async function checkSigil(opts) {
50
50
  return {
51
51
  valid: false,
52
52
  reason: data.reason ?? "no_sigil",
53
- signupUrl: data.signup_url ?? null
53
+ signupUrl: data.signup_url ?? null,
54
+ attributionToken: data.attribution_token ?? null
54
55
  };
55
56
  }
56
57
  async function createPartnerSession(opts) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @provenonce/partner — Provenonce Partner SDK\r\n *\r\n * For skill developers. Wraps GET /api/v1/sigil/check so any skill can verify\r\n * an agent's SIGIL and get a signup URL in one call.\r\n *\r\n * Usage (server-side only — partner key must never be in a client bundle):\r\n *\r\n * import { checkSigil } from '@provenonce/partner'\r\n *\r\n * const result = await checkSigil({\r\n * agentHash: '0x1234...',\r\n * partnerKey: process.env.PROVENONCE_PARTNER_KEY!,\r\n * })\r\n *\r\n * if (!result.valid) {\r\n * return redirect(result.signupUrl)\r\n * }\r\n */\r\n\r\nconst DEFAULT_BASE_URL = 'https://provenonce.io';\r\nconst DEFAULT_TIMEOUT_MS = 5_000;\r\n\r\n// ── Types ─────────────────────────────────────────────────────────────────────\r\n\r\nexport interface SigilCheckOptions {\r\n /** Agent hash to check (0x-prefixed 64-char hex) */\r\n agentHash: string;\r\n /** Your pvp_ partner key — server-side only, never expose to clients */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\n/** Agent has a valid SIGIL */\r\nexport interface SigilCheckValid {\r\n valid: true;\r\n sigil: string;\r\n identityClass: string;\r\n tier: string;\r\n}\r\n\r\n/** Agent has no SIGIL (or is inactive) — signupUrl is pre-built with your ref token */\r\nexport interface SigilCheckInvalid {\r\n valid: false;\r\n reason: 'no_sigil' | 'inactive' | 'not_registered';\r\n /** Pre-built signup URL with your ref token embedded. Redirect the user here. */\r\n signupUrl: string | null;\r\n}\r\n\r\nexport type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;\r\n\r\n// ── Main function ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether an agent has a valid SIGIL.\r\n *\r\n * Server-side only. The `partnerKey` (pvp_...) must never be sent to clients.\r\n *\r\n * On success: returns { valid: true, sigil, identityClass, tier }\r\n * On no SIGIL: returns { valid: false, reason, signupUrl } — redirect to signupUrl\r\n * On auth error: throws ProvenoncePartnerError with status 401/403\r\n * On rate limit: throws ProvenoncePartnerError with status 429\r\n */\r\nexport async function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult> {\r\n const { agentHash, partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!agentHash) throw new ProvenoncePartnerError('agentHash is required', 400);\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/sigil/check?hash=${encodeURIComponent(agentHash)}`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError(\r\n (body as any)?.error ?? 'Partner key rejected',\r\n res.status,\r\n );\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n\r\n if (data.valid === true) {\r\n return {\r\n valid: true,\r\n sigil: data.sigil ?? '',\r\n identityClass: data.identity_class ?? '',\r\n tier: data.tier ?? '',\r\n };\r\n }\r\n\r\n return {\r\n valid: false,\r\n reason: data.reason ?? 'no_sigil',\r\n signupUrl: data.signup_url ?? null,\r\n };\r\n}\r\n\r\n// ── Partner Session Token (D-84) ──────────────────────────────────────────────\r\n\r\nexport interface PartnerSessionOptions {\r\n /** Your pvp_ partner master key */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface PartnerSession {\r\n /** Short-lived pvt_ token — use this for all subsequent API calls */\r\n token: string;\r\n /** ISO 8601 expiry timestamp */\r\n expiresAt: string;\r\n /** Seconds until expiry (nominally 3600) */\r\n expiresInSeconds: number;\r\n}\r\n\r\n/**\r\n * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.\r\n *\r\n * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token\r\n * for all subsequent checkSigil() and other partner API calls.\r\n *\r\n * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment\r\n * (e.g. on server startup or in middleware) and reuse until near expiry.\r\n *\r\n * @example\r\n * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })\r\n * const result = await checkSigil({ agentHash, partnerKey: session.token })\r\n */\r\nexport async function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession> {\r\n const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/partner/token`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n method: 'POST',\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError((body as any)?.error ?? 'Partner key rejected', res.status);\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n return {\r\n token: data.token,\r\n expiresAt: data.expires_at,\r\n expiresInSeconds: data.expires_in_seconds,\r\n };\r\n}\r\n\r\n// ── Error class ───────────────────────────────────────────────────────────────\r\n\r\nexport class ProvenoncePartnerError extends Error {\r\n readonly status: number;\r\n\r\n constructor(message: string, status: number) {\r\n super(message);\r\n this.name = 'ProvenoncePartnerError';\r\n this.status = status;\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @provenonce/partner — Provenonce Partner SDK\r\n *\r\n * For skill developers. Wraps GET /api/v1/sigil/check so any skill can verify\r\n * an agent's SIGIL and get a signup URL in one call.\r\n *\r\n * Usage (server-side only — partner key must never be in a client bundle):\r\n *\r\n * import { checkSigil } from '@provenonce/partner'\r\n *\r\n * const result = await checkSigil({\r\n * agentHash: '0x1234...',\r\n * partnerKey: process.env.PROVENONCE_PARTNER_KEY!,\r\n * })\r\n *\r\n * if (!result.valid) {\r\n * return redirect(result.signupUrl)\r\n * }\r\n */\r\n\r\nconst DEFAULT_BASE_URL = 'https://provenonce.io';\r\nconst DEFAULT_TIMEOUT_MS = 5_000;\r\n\r\n// ── Types ─────────────────────────────────────────────────────────────────────\r\n\r\nexport interface SigilCheckOptions {\r\n /** Agent hash to check (0x-prefixed 64-char hex) */\r\n agentHash: string;\r\n /** Your pvp_ partner key — server-side only, never expose to clients */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\n/** Agent has a valid SIGIL */\r\nexport interface SigilCheckValid {\r\n valid: true;\r\n sigil: string;\r\n identityClass: string;\r\n tier: string;\r\n}\r\n\r\n/** Agent has no SIGIL (or is inactive) — signupUrl is pre-built with your ref token */\r\nexport interface SigilCheckInvalid {\r\n valid: false;\r\n reason: 'no_sigil' | 'inactive' | 'not_registered';\r\n /**\r\n * Pre-built signup URL with your ref token AND attribution token embedded.\r\n * Redirect the user here — attribution is preserved however long they take to register.\r\n * Format: provenonce.io/register?ref={ref_token}&at={pvr_token}\r\n */\r\n signupUrl: string | null;\r\n /**\r\n * Signed attribution token (pvr_...). Already embedded in signupUrl.\r\n * Also pass this as `at` in POST /api/v1/sigil if you handle the\r\n * purchase flow directly (e.g. agent-autonomous payment path).\r\n */\r\n attributionToken: string | null;\r\n}\r\n\r\nexport type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;\r\n\r\n// ── Main function ─────────────────────────────────────────────────────────────\r\n\r\n/**\r\n * Check whether an agent has a valid SIGIL.\r\n *\r\n * Server-side only. The `partnerKey` (pvp_...) must never be sent to clients.\r\n *\r\n * On success: returns { valid: true, sigil, identityClass, tier }\r\n * On no SIGIL: returns { valid: false, reason, signupUrl } — redirect to signupUrl\r\n * On auth error: throws ProvenoncePartnerError with status 401/403\r\n * On rate limit: throws ProvenoncePartnerError with status 429\r\n */\r\nexport async function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult> {\r\n const { agentHash, partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!agentHash) throw new ProvenoncePartnerError('agentHash is required', 400);\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/sigil/check?hash=${encodeURIComponent(agentHash)}`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError(\r\n (body as any)?.error ?? 'Partner key rejected',\r\n res.status,\r\n );\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n\r\n if (data.valid === true) {\r\n return {\r\n valid: true,\r\n sigil: data.sigil ?? '',\r\n identityClass: data.identity_class ?? '',\r\n tier: data.tier ?? '',\r\n };\r\n }\r\n\r\n return {\r\n valid: false,\r\n reason: data.reason ?? 'no_sigil',\r\n signupUrl: data.signup_url ?? null,\r\n attributionToken: data.attribution_token ?? null,\r\n };\r\n}\r\n\r\n// ── Partner Session Token (D-84) ──────────────────────────────────────────────\r\n\r\nexport interface PartnerSessionOptions {\r\n /** Your pvp_ partner master key */\r\n partnerKey: string;\r\n /** Base URL override (default: https://provenonce.io) */\r\n baseUrl?: string;\r\n /** Request timeout in ms (default: 5000) */\r\n timeoutMs?: number;\r\n}\r\n\r\nexport interface PartnerSession {\r\n /** Short-lived pvt_ token — use this for all subsequent API calls */\r\n token: string;\r\n /** ISO 8601 expiry timestamp */\r\n expiresAt: string;\r\n /** Seconds until expiry (nominally 3600) */\r\n expiresInSeconds: number;\r\n}\r\n\r\n/**\r\n * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.\r\n *\r\n * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token\r\n * for all subsequent checkSigil() and other partner API calls.\r\n *\r\n * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment\r\n * (e.g. on server startup or in middleware) and reuse until near expiry.\r\n *\r\n * @example\r\n * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })\r\n * const result = await checkSigil({ agentHash, partnerKey: session.token })\r\n */\r\nexport async function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession> {\r\n const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;\r\n\r\n if (!partnerKey?.startsWith('pvp_')) {\r\n throw new ProvenoncePartnerError('partnerKey must start with pvp_', 400);\r\n }\r\n\r\n const url = `${baseUrl.replace(/\\/$/, '')}/api/v1/partner/token`;\r\n\r\n const controller = new AbortController();\r\n const timer = setTimeout(() => controller.abort(), timeoutMs);\r\n\r\n let res: Response;\r\n try {\r\n res = await fetch(url, {\r\n method: 'POST',\r\n headers: { Authorization: `Bearer ${partnerKey}` },\r\n signal: controller.signal,\r\n });\r\n } catch (err: any) {\r\n clearTimeout(timer);\r\n if (err?.name === 'AbortError') {\r\n throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);\r\n }\r\n throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n\r\n if (res.status === 401 || res.status === 403) {\r\n const body = await res.json().catch(() => ({}));\r\n throw new ProvenoncePartnerError((body as any)?.error ?? 'Partner key rejected', res.status);\r\n }\r\n\r\n if (res.status === 429) {\r\n throw new ProvenoncePartnerError('Rate limit exceeded', 429);\r\n }\r\n\r\n if (!res.ok) {\r\n throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);\r\n }\r\n\r\n const data: any = await res.json();\r\n return {\r\n token: data.token,\r\n expiresAt: data.expires_at,\r\n expiresInSeconds: data.expires_in_seconds,\r\n };\r\n}\r\n\r\n// ── Error class ───────────────────────────────────────────────────────────────\r\n\r\nexport class ProvenoncePartnerError extends Error {\r\n readonly status: number;\r\n\r\n constructor(message: string, status: number) {\r\n super(message);\r\n this.name = 'ProvenoncePartnerError';\r\n this.status = status;\r\n Object.setPrototypeOf(this, new.target.prototype);\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@provenonce/partner",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Provenonce Partner SDK — SIGIL verification for skill developers",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",