@provenonce/partner 1.0.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
  /**
@@ -53,9 +63,39 @@ type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;
53
63
  * On rate limit: throws ProvenoncePartnerError with status 429
54
64
  */
55
65
  declare function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult>;
66
+ interface PartnerSessionOptions {
67
+ /** Your pvp_ partner master key */
68
+ partnerKey: string;
69
+ /** Base URL override (default: https://provenonce.io) */
70
+ baseUrl?: string;
71
+ /** Request timeout in ms (default: 5000) */
72
+ timeoutMs?: number;
73
+ }
74
+ interface PartnerSession {
75
+ /** Short-lived pvt_ token — use this for all subsequent API calls */
76
+ token: string;
77
+ /** ISO 8601 expiry timestamp */
78
+ expiresAt: string;
79
+ /** Seconds until expiry (nominally 3600) */
80
+ expiresInSeconds: number;
81
+ }
82
+ /**
83
+ * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.
84
+ *
85
+ * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token
86
+ * for all subsequent checkSigil() and other partner API calls.
87
+ *
88
+ * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment
89
+ * (e.g. on server startup or in middleware) and reuse until near expiry.
90
+ *
91
+ * @example
92
+ * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })
93
+ * const result = await checkSigil({ agentHash, partnerKey: session.token })
94
+ */
95
+ declare function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession>;
56
96
  declare class ProvenoncePartnerError extends Error {
57
97
  readonly status: number;
58
98
  constructor(message: string, status: number);
59
99
  }
60
100
 
61
- export { ProvenoncePartnerError, type SigilCheckInvalid, type SigilCheckOptions, type SigilCheckResult, type SigilCheckValid, checkSigil };
101
+ export { type PartnerSession, type PartnerSessionOptions, ProvenoncePartnerError, type SigilCheckInvalid, type SigilCheckOptions, type SigilCheckResult, type SigilCheckValid, checkSigil, createPartnerSession };
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
  /**
@@ -53,9 +63,39 @@ type SigilCheckResult = SigilCheckValid | SigilCheckInvalid;
53
63
  * On rate limit: throws ProvenoncePartnerError with status 429
54
64
  */
55
65
  declare function checkSigil(opts: SigilCheckOptions): Promise<SigilCheckResult>;
66
+ interface PartnerSessionOptions {
67
+ /** Your pvp_ partner master key */
68
+ partnerKey: string;
69
+ /** Base URL override (default: https://provenonce.io) */
70
+ baseUrl?: string;
71
+ /** Request timeout in ms (default: 5000) */
72
+ timeoutMs?: number;
73
+ }
74
+ interface PartnerSession {
75
+ /** Short-lived pvt_ token — use this for all subsequent API calls */
76
+ token: string;
77
+ /** ISO 8601 expiry timestamp */
78
+ expiresAt: string;
79
+ /** Seconds until expiry (nominally 3600) */
80
+ expiresInSeconds: number;
81
+ }
82
+ /**
83
+ * Exchange your long-lived pvp_ partner key for a short-lived pvt_ session token.
84
+ *
85
+ * Per D-84: use the pvp_ key only to mint tokens. Use the returned pvt_ token
86
+ * for all subsequent checkSigil() and other partner API calls.
87
+ *
88
+ * The pvt_ token is valid for 1 hour. Recommended: mint once per deployment
89
+ * (e.g. on server startup or in middleware) and reuse until near expiry.
90
+ *
91
+ * @example
92
+ * const session = await createPartnerSession({ partnerKey: process.env.PROVENONCE_PARTNER_KEY! })
93
+ * const result = await checkSigil({ agentHash, partnerKey: session.token })
94
+ */
95
+ declare function createPartnerSession(opts: PartnerSessionOptions): Promise<PartnerSession>;
56
96
  declare class ProvenoncePartnerError extends Error {
57
97
  readonly status: number;
58
98
  constructor(message: string, status: number);
59
99
  }
60
100
 
61
- export { ProvenoncePartnerError, type SigilCheckInvalid, type SigilCheckOptions, type SigilCheckResult, type SigilCheckValid, checkSigil };
101
+ export { type PartnerSession, type PartnerSessionOptions, ProvenoncePartnerError, type SigilCheckInvalid, type SigilCheckOptions, type SigilCheckResult, type SigilCheckValid, checkSigil, createPartnerSession };
package/dist/index.js CHANGED
@@ -21,7 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ProvenoncePartnerError: () => ProvenoncePartnerError,
24
- checkSigil: () => checkSigil
24
+ checkSigil: () => checkSigil,
25
+ createPartnerSession: () => createPartnerSession
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
27
28
  var DEFAULT_BASE_URL = "https://provenonce.io";
@@ -75,7 +76,49 @@ async function checkSigil(opts) {
75
76
  return {
76
77
  valid: false,
77
78
  reason: data.reason ?? "no_sigil",
78
- signupUrl: data.signup_url ?? null
79
+ signupUrl: data.signup_url ?? null,
80
+ attributionToken: data.attribution_token ?? null
81
+ };
82
+ }
83
+ async function createPartnerSession(opts) {
84
+ const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;
85
+ if (!partnerKey?.startsWith("pvp_")) {
86
+ throw new ProvenoncePartnerError("partnerKey must start with pvp_", 400);
87
+ }
88
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/partner/token`;
89
+ const controller = new AbortController();
90
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
91
+ let res;
92
+ try {
93
+ res = await fetch(url, {
94
+ method: "POST",
95
+ headers: { Authorization: `Bearer ${partnerKey}` },
96
+ signal: controller.signal
97
+ });
98
+ } catch (err) {
99
+ clearTimeout(timer);
100
+ if (err?.name === "AbortError") {
101
+ throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);
102
+ }
103
+ throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);
104
+ } finally {
105
+ clearTimeout(timer);
106
+ }
107
+ if (res.status === 401 || res.status === 403) {
108
+ const body = await res.json().catch(() => ({}));
109
+ throw new ProvenoncePartnerError(body?.error ?? "Partner key rejected", res.status);
110
+ }
111
+ if (res.status === 429) {
112
+ throw new ProvenoncePartnerError("Rate limit exceeded", 429);
113
+ }
114
+ if (!res.ok) {
115
+ throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);
116
+ }
117
+ const data = await res.json();
118
+ return {
119
+ token: data.token,
120
+ expiresAt: data.expires_at,
121
+ expiresInSeconds: data.expires_in_seconds
79
122
  };
80
123
  }
81
124
  var ProvenoncePartnerError = class extends Error {
@@ -89,6 +132,7 @@ var ProvenoncePartnerError = class extends Error {
89
132
  // Annotate the CommonJS export names for ESM import in node:
90
133
  0 && (module.exports = {
91
134
  ProvenoncePartnerError,
92
- checkSigil
135
+ checkSigil,
136
+ createPartnerSession
93
137
  });
94
138
  //# sourceMappingURL=index.js.map
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// ── 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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AA6C3B,eAAsB,WAAW,MAAoD;AACnF,QAAM,EAAE,WAAW,YAAY,UAAU,kBAAkB,YAAY,mBAAmB,IAAI;AAE9F,MAAI,CAAC,UAAW,OAAM,IAAI,uBAAuB,yBAAyB,GAAG;AAC7E,MAAI,CAAC,YAAY,WAAW,MAAM,GAAG;AACnC,UAAM,IAAI,uBAAuB,mCAAmC,GAAG;AAAA,EACzE;AAEA,QAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,4BAA4B,mBAAmB,SAAS,CAAC;AAElG,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB,SAAS,EAAE,eAAe,UAAU,UAAU,GAAG;AAAA,MACjD,QAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,EACH,SAAS,KAAU;AACjB,iBAAa,KAAK;AAClB,QAAI,KAAK,SAAS,cAAc;AAC9B,YAAM,IAAI,uBAAuB,2BAA2B,SAAS,MAAM,GAAG;AAAA,IAChF;AACA,UAAM,IAAI,uBAAuB,kBAAkB,KAAK,WAAW,GAAG,IAAI,CAAC;AAAA,EAC7E,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AAEA,MAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,UAAM,IAAI;AAAA,MACP,MAAc,SAAS;AAAA,MACxB,IAAI;AAAA,IACN;AAAA,EACF;AAEA,MAAI,IAAI,WAAW,KAAK;AACtB,UAAM,IAAI,uBAAuB,uBAAuB,GAAG;AAAA,EAC7D;AAEA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,uBAAuB,wBAAwB,IAAI,MAAM,IAAI,IAAI,MAAM;AAAA,EACnF;AAEA,QAAM,OAAY,MAAM,IAAI,KAAK;AAEjC,MAAI,KAAK,UAAU,MAAM;AACvB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,KAAK,SAAS;AAAA,MACrB,eAAe,KAAK,kBAAkB;AAAA,MACtC,MAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ,KAAK,UAAU;AAAA,IACvB,WAAW,KAAK,cAAc;AAAA,EAChC;AACF;AAIO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAGhD,YAAY,SAAiB,QAAgB;AAC3C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;","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,49 @@ 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
55
+ };
56
+ }
57
+ async function createPartnerSession(opts) {
58
+ const { partnerKey, baseUrl = DEFAULT_BASE_URL, timeoutMs = DEFAULT_TIMEOUT_MS } = opts;
59
+ if (!partnerKey?.startsWith("pvp_")) {
60
+ throw new ProvenoncePartnerError("partnerKey must start with pvp_", 400);
61
+ }
62
+ const url = `${baseUrl.replace(/\/$/, "")}/api/v1/partner/token`;
63
+ const controller = new AbortController();
64
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
65
+ let res;
66
+ try {
67
+ res = await fetch(url, {
68
+ method: "POST",
69
+ headers: { Authorization: `Bearer ${partnerKey}` },
70
+ signal: controller.signal
71
+ });
72
+ } catch (err) {
73
+ clearTimeout(timer);
74
+ if (err?.name === "AbortError") {
75
+ throw new ProvenoncePartnerError(`Request timed out after ${timeoutMs}ms`, 408);
76
+ }
77
+ throw new ProvenoncePartnerError(`Network error: ${err?.message ?? err}`, 0);
78
+ } finally {
79
+ clearTimeout(timer);
80
+ }
81
+ if (res.status === 401 || res.status === 403) {
82
+ const body = await res.json().catch(() => ({}));
83
+ throw new ProvenoncePartnerError(body?.error ?? "Partner key rejected", res.status);
84
+ }
85
+ if (res.status === 429) {
86
+ throw new ProvenoncePartnerError("Rate limit exceeded", 429);
87
+ }
88
+ if (!res.ok) {
89
+ throw new ProvenoncePartnerError(`Unexpected response: ${res.status}`, res.status);
90
+ }
91
+ const data = await res.json();
92
+ return {
93
+ token: data.token,
94
+ expiresAt: data.expires_at,
95
+ expiresInSeconds: data.expires_in_seconds
54
96
  };
55
97
  }
56
98
  var ProvenoncePartnerError = class extends Error {
@@ -63,6 +105,7 @@ var ProvenoncePartnerError = class extends Error {
63
105
  };
64
106
  export {
65
107
  ProvenoncePartnerError,
66
- checkSigil
108
+ checkSigil,
109
+ createPartnerSession
67
110
  };
68
111
  //# sourceMappingURL=index.mjs.map
@@ -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// ── 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":";AAoBA,IAAM,mBAAmB;AACzB,IAAM,qBAAqB;AA6C3B,eAAsB,WAAW,MAAoD;AACnF,QAAM,EAAE,WAAW,YAAY,UAAU,kBAAkB,YAAY,mBAAmB,IAAI;AAE9F,MAAI,CAAC,UAAW,OAAM,IAAI,uBAAuB,yBAAyB,GAAG;AAC7E,MAAI,CAAC,YAAY,WAAW,MAAM,GAAG;AACnC,UAAM,IAAI,uBAAuB,mCAAmC,GAAG;AAAA,EACzE;AAEA,QAAM,MAAM,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC,4BAA4B,mBAAmB,SAAS,CAAC;AAElG,QAAM,aAAa,IAAI,gBAAgB;AACvC,QAAM,QAAQ,WAAW,MAAM,WAAW,MAAM,GAAG,SAAS;AAE5D,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB,SAAS,EAAE,eAAe,UAAU,UAAU,GAAG;AAAA,MACjD,QAAQ,WAAW;AAAA,IACrB,CAAC;AAAA,EACH,SAAS,KAAU;AACjB,iBAAa,KAAK;AAClB,QAAI,KAAK,SAAS,cAAc;AAC9B,YAAM,IAAI,uBAAuB,2BAA2B,SAAS,MAAM,GAAG;AAAA,IAChF;AACA,UAAM,IAAI,uBAAuB,kBAAkB,KAAK,WAAW,GAAG,IAAI,CAAC;AAAA,EAC7E,UAAE;AACA,iBAAa,KAAK;AAAA,EACpB;AAEA,MAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,UAAM,IAAI;AAAA,MACP,MAAc,SAAS;AAAA,MACxB,IAAI;AAAA,IACN;AAAA,EACF;AAEA,MAAI,IAAI,WAAW,KAAK;AACtB,UAAM,IAAI,uBAAuB,uBAAuB,GAAG;AAAA,EAC7D;AAEA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,uBAAuB,wBAAwB,IAAI,MAAM,IAAI,IAAI,MAAM;AAAA,EACnF;AAEA,QAAM,OAAY,MAAM,IAAI,KAAK;AAEjC,MAAI,KAAK,UAAU,MAAM;AACvB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,KAAK,SAAS;AAAA,MACrB,eAAe,KAAK,kBAAkB;AAAA,MACtC,MAAM,KAAK,QAAQ;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ,KAAK,UAAU;AAAA,IACvB,WAAW,KAAK,cAAc;AAAA,EAChC;AACF;AAIO,IAAM,yBAAN,cAAqC,MAAM;AAAA,EAGhD,YAAY,SAAiB,QAAgB;AAC3C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,WAAO,eAAe,MAAM,WAAW,SAAS;AAAA,EAClD;AACF;","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.0.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",