@sekyro/node 0.1.0-rc.5 → 0.1.0-rc.6
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/CHANGELOG.md +10 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +35 -2
- package/dist/index.d.ts +35 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/sbom.cdx.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @sekyro/node
|
|
2
2
|
|
|
3
|
+
## 0.1.0-rc.6
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 8bc8320: `subject.reuse` accepts an identity document: `{ document: { type, issuingCountry, number } }` (`SubjectReuseDocument`; `type` is `national_id`, `passport` or `residence_permit`, `issuingCountry` ISO alpha-2 or alpha-3). Still exactly one target per session.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 82c4898: `CreateSessionInput.assistedBy` and `Session.assistedBy`: your own reference for the agent filming the person in an assisted-capture flow.
|
|
12
|
+
|
|
3
13
|
## 0.1.0-rc.5
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var src_exports={};__export(src_exports,{DEFAULT_BASE_URL:()=>DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS:()=>DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER:()=>LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER:()=>SEKYRO_SIGNATURE_HEADER,Sekyro:()=>Sekyro,SekyroApiError:()=>SekyroApiError,SekyroConfigError:()=>SekyroConfigError,SekyroWebhookError:()=>SekyroWebhookError,isFlowError:()=>isFlowError,registryFromAnrpts:()=>registryFromAnrpts,signatureFromHeaders:()=>signatureFromHeaders,verifyWebhook:()=>verifyWebhook});module.exports=__toCommonJS(src_exports);var WEBHOOK_MESSAGES={invalid_signature:"No v1 signature in the header matches this body and secret",stale:"Delivery timestamp is outside the tolerance window",malformed:"Signature header or body is not in the expected format"},SekyroWebhookError=class extends Error{name="SekyroWebhookError";code;constructor(code,message=WEBHOOK_MESSAGES[code]){super(message),this.code=code}},CONFIG_MESSAGES={missing_api_key:"Sekyro AI: `apiKey` is required",invalid_base_url:"Sekyro AI: `baseUrl` must be an https: URL (http: is allowed only for localhost, 127.0.0.1 or [::1])",invalid_registry_record:"Sekyro AI: the ANRPTS answer can't be used as a registry record"},SekyroConfigError=class extends TypeError{name="SekyroConfigError";code;constructor(code,message=CONFIG_MESSAGES[code]){super(message),this.code=code}},SekyroApiError=class extends Error{name="SekyroApiError";status;code;requestId;details;retryable;constructor(init){super(init.message,init.cause===void 0?void 0:{cause:init.cause}),this.status=init.status,this.code=init.code,this.requestId=init.requestId,this.details=init.details,this.retryable=isRetryable(init.status,init.code)}},FLOW_ERROR_CODES=new Set(["flow_not_found","flow_not_published","flow_archived","override_invalid","override_widens_flow","reuse_disabled","choice_not_found","choice_locked","choice_option_unavailable"]),FLOW_REF_CODES=new Set(["flow_not_published","flow_archived","reuse_disabled"]),isRecord=x=>typeof x=="object"&&x!==null&&!Array.isArray(x),isStringArray=x=>Array.isArray(x)&&x.every(s=>typeof s=="string");function isIssue(x){return isRecord(x)&&typeof x.code=="string"&&typeof x.message=="string"}function hasFlowDetails(code,details){if(!isRecord(details)||!Array.isArray(details.issues)||!details.issues.every(isIssue))return!1;if(code==="override_widens_flow")return isStringArray(details.fields);if(FLOW_REF_CODES.has(code)){let flow=details.flow;return isRecord(flow)&&typeof flow.id=="string"&&typeof flow.slug=="string"}return!0}function isFlowError(err,...codes){return!(err instanceof SekyroApiError)||!FLOW_ERROR_CODES.has(err.code)||codes.length>0&&!codes.includes(err.code)?!1:hasFlowDetails(err.code,err.details)}function isRetryable(status,code){return code==="network"||code==="timeout"||code==="idempotency_in_progress"||status===429?!0:status>=500&&status<=599}var SDK_VERSION="0.1.0-rc.5";var USER_AGENT=`@sekyro/node/${SDK_VERSION}`,DEFAULT_BASE_URL="https://api.sekyro.ai/api/v2",DEFAULT_TIMEOUT_MS=3e4;function isSuccessEnvelope(value){return typeof value=="object"&&value!==null&&value.success===!0&&"data"in value}function isErrorEnvelope(value){if(typeof value!="object"||value===null)return!1;let v=value;if(v.status!=="error"||typeof v.error!="object"||v.error===null)return!1;let e=v.error;return typeof e.code=="string"&&typeof e.message=="string"}function isAbortLike(err){if(typeof err!="object"||err===null)return!1;let name=err.name;return name==="TimeoutError"||name==="AbortError"}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function assertSafeBaseUrl(baseUrl){let url;try{url=new URL(baseUrl)}catch{throw new SekyroConfigError("invalid_base_url")}if(url.protocol!=="https:"&&!(url.protocol==="http:"&&LOOPBACK_HOSTS.has(url.hostname)))throw new SekyroConfigError("invalid_base_url")}var Transport=class{apiKey;baseUrl;timeoutMs;fetchImpl;constructor(opts){let baseUrl=(opts.baseUrl??DEFAULT_BASE_URL).replace(/\/+$/,"");assertSafeBaseUrl(baseUrl),this.apiKey=opts.apiKey,this.baseUrl=baseUrl,this.timeoutMs=opts.timeoutMs??DEFAULT_TIMEOUT_MS,this.fetchImpl=opts.fetch??globalThis.fetch}async call(method,path,body,idempotencyKey){let headers={authorization:`Bearer ${this.apiKey}`,accept:"application/json","user-agent":USER_AGENT};body!==void 0&&(headers["content-type"]="application/json"),idempotencyKey!==void 0&&(headers["x-idempotency-key"]=idempotencyKey);let init={method,headers,signal:AbortSignal.timeout(this.timeoutMs)};body!==void 0&&(init.body=JSON.stringify(body));let res;try{res=await this.fetchImpl(`${this.baseUrl}${path}`,init)}catch(err){throw isAbortLike(err)?new SekyroApiError({status:0,code:"timeout",message:`Request timed out after ${this.timeoutMs}ms`,cause:err}):new SekyroApiError({status:0,code:"network",message:`Network error: ${err instanceof Error?err.message:String(err)}`,cause:err})}let text2=await res.text(),parsed,parseError;try{parsed=text2.length>0?JSON.parse(text2):void 0}catch(err){parseError=err}if(!res.ok){if(isErrorEnvelope(parsed)){let init2={status:res.status,code:parsed.error.code,message:parsed.error.message};throw parsed.error.request_id!==void 0&&(init2.requestId=parsed.error.request_id),parsed.error.details!==void 0&&(init2.details=parsed.error.details),new SekyroApiError(init2)}throw new SekyroApiError({status:res.status,code:"http_error",message:`HTTP ${res.status}${res.statusText?` ${res.statusText}`:""}`})}if(!isSuccessEnvelope(parsed))throw new SekyroApiError({status:res.status,code:"malformed_response",message:"Response is not a `{ success: true, data }` envelope",cause:parseError});return parsed.data}},SessionsApi=class{constructor(call){this.call=call}call;async create(input={},opts={}){let wire=await this.call("POST","/sessions",input,opts.idempotencyKey);return{id:wire.id,status:wire.status,clientToken:wire.client_token,hostedUrl:wire.hosted_url,...wire.flow!==void 0?{flow:wire.flow}:{},steps:wire.steps,expiresAt:wire.expiresAt}}async selectMethod(id,method){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.selectMethod: `id` must be a non-empty string");return this.call("POST",`/sessions/${encodeURIComponent(id)}/method`,{method})}async get(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.get: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}`)}async portrait(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.portrait: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}/portrait?format=url`)}};function assertId(method,id){if(typeof id!="string"||id.length===0)throw new TypeError(`subjects.${method}: \`id\` must be a non-empty string`)}var SubjectsApi=class{constructor(call){this.call=call}call;async get(id){return assertId("get",id),this.call("GET",`/subjects/${encodeURIComponent(id)}`)}async list(query){if(typeof query?.externalRef!="string"||query.externalRef.length===0)throw new TypeError("subjects.list: `externalRef` must be a non-empty string");let qs=new URLSearchParams({externalRef:query.externalRef});return this.call("GET",`/subjects?${qs.toString()}`)}async revoke(id,input={},opts={}){return assertId("revoke",id),this.call("POST",`/subjects/${encodeURIComponent(id)}/revoke`,input,opts.idempotencyKey)}async delete(id){return assertId("delete",id),this.call("DELETE",`/subjects/${encodeURIComponent(id)}`)}},Sekyro=class{sessions;subjects;#transport;constructor(opts){if(typeof opts?.apiKey!="string"||opts.apiKey.length===0)throw new SekyroConfigError("missing_api_key");let transport=new Transport(opts);this.#transport=transport,this.sessions=new SessionsApi(transport.call.bind(transport)),this.subjects=new SubjectsApi(transport.call.bind(transport))}async listFlows(){return this.#transport.call("GET","/flows")}};function registryFromAnrpts(response,options){let p=response?.personne??{},required=(field,value)=>{let s=text(value);if(s===void 0)throw new SekyroConfigError("invalid_registry_record",`Sekyro AI: the ANRPTS answer has no usable \`${field}\``);return s},birthDate=isoDay(p.dateNaissance);if(birthDate===void 0)throw new SekyroConfigError("invalid_registry_record","Sekyro AI: the ANRPTS answer has no usable `personne.dateNaissance`");let photo=required("photo",response?.photo).replace(/\s+/g,""),fetchedAt=new Date(options?.fetchedAt??Number.NaN);if(Number.isNaN(fetchedAt.getTime()))throw new SekyroConfigError("invalid_registry_record","Sekyro AI: `fetchedAt` (when your system received the ANRPTS answer) is missing or not a valid date");let record={nni:required("personne.nni",p.nni),firstNameFr:required("personne.prenomFr",p.prenomFr),lastNameFr:required("personne.patronymeFr",p.patronymeFr),firstNameAr:required("personne.prenomAr",p.prenomAr),lastNameAr:required("personne.patronymeAr",p.patronymeAr),birthDate,photo,fetchedAt:fetchedAt.toISOString()},optional=[["fatherNameFr",p.perePrenomFr],["fatherNameAr",p.perePrenomAr],["birthPlaceFr",p.lieuNaissanceFr],["birthPlaceAr",p.lieuNaissanceAr]];for(let[key,value]of optional){let s=text(value);s!==void 0&&(record[key]=s)}let sex=text(p.sexeCode)?.toUpperCase();(sex==="M"||sex==="F")&&(record.sex=sex);let nationalities=Array.isArray(p.nationalities)?p.nationalities.map(text).filter(n=>n!==void 0).slice(0,5):[];nationalities.length>0&&(record.nationalities=nationalities);let photoDate=isoDay(response?.datePhoto);return photoDate!==void 0&&(record.photoDate=photoDate),record}function text(value){if(typeof value!="string")return;let s=value.trim();return s.length>0?s:void 0}function isoDay(value){let s=text(value);if(s===void 0)return;let iso=/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/.exec(s),fr=/^(\d{2})\/(\d{2})\/(\d{4})$/.exec(s),[y,m,d]=iso?[iso[1],iso[2],iso[3]]:fr?[fr[3],fr[2],fr[1]]:[];if(y===void 0||m===void 0||d===void 0)return;let t=new Date(Date.UTC(Number(y),Number(m)-1,Number(d)));return t.getUTCFullYear()===Number(y)&&t.getUTCMonth()===Number(m)-1&&t.getUTCDate()===Number(d)?`${y}-${m}-${d}`:void 0}var import_node_crypto=require("crypto");var SEKYRO_SIGNATURE_HEADER="x-sekyro-signature",LEGACY_SIGNATURE_HEADER="x-ibtikar-signature";function signatureFromHeaders(headers){return readHeader(headers,SEKYRO_SIGNATURE_HEADER)??readHeader(headers,LEGACY_SIGNATURE_HEADER)}function readHeader(headers,name){if(typeof headers.get=="function"){let v2=headers.get(name);return v2===null||v2===""?void 0:v2}let record=headers,key=Object.keys(record).find(k=>k.toLowerCase()===name);if(key===void 0)return;let raw=record[key],v=Array.isArray(raw)?raw[0]:raw;return v===void 0||v===""?void 0:v}var HEX64=/^[0-9a-f]{64}$/i;function verifyWebhook(rawBody,header,secret,opts={}){if(!header||!secret)throw new SekyroWebhookError("invalid_signature");let parts=header.split(",").map(part=>{let trimmed=part.trim(),eq=trimmed.indexOf("=");return eq===-1?[trimmed,""]:[trimmed.slice(0,eq).trim(),trimmed.slice(eq+1).trim()]}),tRaw=parts.find(([k])=>k==="t")?.[1],t=tRaw!==void 0&&/^\d+$/.test(tRaw)?Number(tRaw):Number.NaN,sigs=parts.filter(([k])=>k==="v1").map(([,v])=>v);if(!Number.isSafeInteger(t)||sigs.length===0)throw new SekyroWebhookError("malformed");let nowSec=Math.floor((opts.now?.()??Date.now())/1e3),tolerance=opts.toleranceSec??300;if(Math.abs(nowSec-t)>tolerance)throw new SekyroWebhookError("stale");let expected=(0,import_node_crypto.createHmac)("sha256",secret).update(`${t}.${rawBody}`).digest();if(!sigs.some(hex=>{if(!HEX64.test(hex))return!1;let got=Buffer.from(hex,"hex");return got.length===expected.length&&(0,import_node_crypto.timingSafeEqual)(got,expected)}))throw new SekyroWebhookError("invalid_signature");let parsed;try{parsed=JSON.parse(rawBody)}catch{throw new SekyroWebhookError("malformed","Signed body is not valid JSON")}if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))throw new SekyroWebhookError("malformed","Signed body is not a JSON object");return parsed}0&&(module.exports={DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER,Sekyro,SekyroApiError,SekyroConfigError,SekyroWebhookError,isFlowError,registryFromAnrpts,signatureFromHeaders,verifyWebhook});
|
|
1
|
+
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:!0})},__copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:!0}),mod);var src_exports={};__export(src_exports,{DEFAULT_BASE_URL:()=>DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS:()=>DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER:()=>LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER:()=>SEKYRO_SIGNATURE_HEADER,Sekyro:()=>Sekyro,SekyroApiError:()=>SekyroApiError,SekyroConfigError:()=>SekyroConfigError,SekyroWebhookError:()=>SekyroWebhookError,isFlowError:()=>isFlowError,registryFromAnrpts:()=>registryFromAnrpts,signatureFromHeaders:()=>signatureFromHeaders,verifyWebhook:()=>verifyWebhook});module.exports=__toCommonJS(src_exports);var WEBHOOK_MESSAGES={invalid_signature:"No v1 signature in the header matches this body and secret",stale:"Delivery timestamp is outside the tolerance window",malformed:"Signature header or body is not in the expected format"},SekyroWebhookError=class extends Error{name="SekyroWebhookError";code;constructor(code,message=WEBHOOK_MESSAGES[code]){super(message),this.code=code}},CONFIG_MESSAGES={missing_api_key:"Sekyro AI: `apiKey` is required",invalid_base_url:"Sekyro AI: `baseUrl` must be an https: URL (http: is allowed only for localhost, 127.0.0.1 or [::1])",invalid_registry_record:"Sekyro AI: the ANRPTS answer can't be used as a registry record"},SekyroConfigError=class extends TypeError{name="SekyroConfigError";code;constructor(code,message=CONFIG_MESSAGES[code]){super(message),this.code=code}},SekyroApiError=class extends Error{name="SekyroApiError";status;code;requestId;details;retryable;constructor(init){super(init.message,init.cause===void 0?void 0:{cause:init.cause}),this.status=init.status,this.code=init.code,this.requestId=init.requestId,this.details=init.details,this.retryable=isRetryable(init.status,init.code)}},FLOW_ERROR_CODES=new Set(["flow_not_found","flow_not_published","flow_archived","override_invalid","override_widens_flow","reuse_disabled","choice_not_found","choice_locked","choice_option_unavailable"]),FLOW_REF_CODES=new Set(["flow_not_published","flow_archived","reuse_disabled"]),isRecord=x=>typeof x=="object"&&x!==null&&!Array.isArray(x),isStringArray=x=>Array.isArray(x)&&x.every(s=>typeof s=="string");function isIssue(x){return isRecord(x)&&typeof x.code=="string"&&typeof x.message=="string"}function hasFlowDetails(code,details){if(!isRecord(details)||!Array.isArray(details.issues)||!details.issues.every(isIssue))return!1;if(code==="override_widens_flow")return isStringArray(details.fields);if(FLOW_REF_CODES.has(code)){let flow=details.flow;return isRecord(flow)&&typeof flow.id=="string"&&typeof flow.slug=="string"}return!0}function isFlowError(err,...codes){return!(err instanceof SekyroApiError)||!FLOW_ERROR_CODES.has(err.code)||codes.length>0&&!codes.includes(err.code)?!1:hasFlowDetails(err.code,err.details)}function isRetryable(status,code){return code==="network"||code==="timeout"||code==="idempotency_in_progress"||status===429?!0:status>=500&&status<=599}var SDK_VERSION="0.1.0-rc.6";var USER_AGENT=`@sekyro/node/${SDK_VERSION}`,DEFAULT_BASE_URL="https://api.sekyro.ai/api/v2",DEFAULT_TIMEOUT_MS=3e4;function isSuccessEnvelope(value){return typeof value=="object"&&value!==null&&value.success===!0&&"data"in value}function isErrorEnvelope(value){if(typeof value!="object"||value===null)return!1;let v=value;if(v.status!=="error"||typeof v.error!="object"||v.error===null)return!1;let e=v.error;return typeof e.code=="string"&&typeof e.message=="string"}function isAbortLike(err){if(typeof err!="object"||err===null)return!1;let name=err.name;return name==="TimeoutError"||name==="AbortError"}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function assertSafeBaseUrl(baseUrl){let url;try{url=new URL(baseUrl)}catch{throw new SekyroConfigError("invalid_base_url")}if(url.protocol!=="https:"&&!(url.protocol==="http:"&&LOOPBACK_HOSTS.has(url.hostname)))throw new SekyroConfigError("invalid_base_url")}var Transport=class{apiKey;baseUrl;timeoutMs;fetchImpl;constructor(opts){let baseUrl=(opts.baseUrl??DEFAULT_BASE_URL).replace(/\/+$/,"");assertSafeBaseUrl(baseUrl),this.apiKey=opts.apiKey,this.baseUrl=baseUrl,this.timeoutMs=opts.timeoutMs??DEFAULT_TIMEOUT_MS,this.fetchImpl=opts.fetch??globalThis.fetch}async call(method,path,body,idempotencyKey){let headers={authorization:`Bearer ${this.apiKey}`,accept:"application/json","user-agent":USER_AGENT};body!==void 0&&(headers["content-type"]="application/json"),idempotencyKey!==void 0&&(headers["x-idempotency-key"]=idempotencyKey);let init={method,headers,signal:AbortSignal.timeout(this.timeoutMs)};body!==void 0&&(init.body=JSON.stringify(body));let res;try{res=await this.fetchImpl(`${this.baseUrl}${path}`,init)}catch(err){throw isAbortLike(err)?new SekyroApiError({status:0,code:"timeout",message:`Request timed out after ${this.timeoutMs}ms`,cause:err}):new SekyroApiError({status:0,code:"network",message:`Network error: ${err instanceof Error?err.message:String(err)}`,cause:err})}let text2=await res.text(),parsed,parseError;try{parsed=text2.length>0?JSON.parse(text2):void 0}catch(err){parseError=err}if(!res.ok){if(isErrorEnvelope(parsed)){let init2={status:res.status,code:parsed.error.code,message:parsed.error.message};throw parsed.error.request_id!==void 0&&(init2.requestId=parsed.error.request_id),parsed.error.details!==void 0&&(init2.details=parsed.error.details),new SekyroApiError(init2)}throw new SekyroApiError({status:res.status,code:"http_error",message:`HTTP ${res.status}${res.statusText?` ${res.statusText}`:""}`})}if(!isSuccessEnvelope(parsed))throw new SekyroApiError({status:res.status,code:"malformed_response",message:"Response is not a `{ success: true, data }` envelope",cause:parseError});return parsed.data}},SessionsApi=class{constructor(call){this.call=call}call;async create(input={},opts={}){let wire=await this.call("POST","/sessions",input,opts.idempotencyKey);return{id:wire.id,status:wire.status,clientToken:wire.client_token,hostedUrl:wire.hosted_url,...wire.flow!==void 0?{flow:wire.flow}:{},steps:wire.steps,expiresAt:wire.expiresAt}}async selectMethod(id,method){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.selectMethod: `id` must be a non-empty string");return this.call("POST",`/sessions/${encodeURIComponent(id)}/method`,{method})}async get(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.get: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}`)}async portrait(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.portrait: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}/portrait?format=url`)}};function assertId(method,id){if(typeof id!="string"||id.length===0)throw new TypeError(`subjects.${method}: \`id\` must be a non-empty string`)}var SubjectsApi=class{constructor(call){this.call=call}call;async get(id){return assertId("get",id),this.call("GET",`/subjects/${encodeURIComponent(id)}`)}async list(query){if(typeof query?.externalRef!="string"||query.externalRef.length===0)throw new TypeError("subjects.list: `externalRef` must be a non-empty string");let qs=new URLSearchParams({externalRef:query.externalRef});return this.call("GET",`/subjects?${qs.toString()}`)}async revoke(id,input={},opts={}){return assertId("revoke",id),this.call("POST",`/subjects/${encodeURIComponent(id)}/revoke`,input,opts.idempotencyKey)}async delete(id){return assertId("delete",id),this.call("DELETE",`/subjects/${encodeURIComponent(id)}`)}},Sekyro=class{sessions;subjects;#transport;constructor(opts){if(typeof opts?.apiKey!="string"||opts.apiKey.length===0)throw new SekyroConfigError("missing_api_key");let transport=new Transport(opts);this.#transport=transport,this.sessions=new SessionsApi(transport.call.bind(transport)),this.subjects=new SubjectsApi(transport.call.bind(transport))}async listFlows(){return this.#transport.call("GET","/flows")}};function registryFromAnrpts(response,options){let p=response?.personne??{},required=(field,value)=>{let s=text(value);if(s===void 0)throw new SekyroConfigError("invalid_registry_record",`Sekyro AI: the ANRPTS answer has no usable \`${field}\``);return s},birthDate=isoDay(p.dateNaissance);if(birthDate===void 0)throw new SekyroConfigError("invalid_registry_record","Sekyro AI: the ANRPTS answer has no usable `personne.dateNaissance`");let photo=required("photo",response?.photo).replace(/\s+/g,""),fetchedAt=new Date(options?.fetchedAt??Number.NaN);if(Number.isNaN(fetchedAt.getTime()))throw new SekyroConfigError("invalid_registry_record","Sekyro AI: `fetchedAt` (when your system received the ANRPTS answer) is missing or not a valid date");let record={nni:required("personne.nni",p.nni),firstNameFr:required("personne.prenomFr",p.prenomFr),lastNameFr:required("personne.patronymeFr",p.patronymeFr),firstNameAr:required("personne.prenomAr",p.prenomAr),lastNameAr:required("personne.patronymeAr",p.patronymeAr),birthDate,photo,fetchedAt:fetchedAt.toISOString()},optional=[["fatherNameFr",p.perePrenomFr],["fatherNameAr",p.perePrenomAr],["birthPlaceFr",p.lieuNaissanceFr],["birthPlaceAr",p.lieuNaissanceAr]];for(let[key,value]of optional){let s=text(value);s!==void 0&&(record[key]=s)}let sex=text(p.sexeCode)?.toUpperCase();(sex==="M"||sex==="F")&&(record.sex=sex);let nationalities=Array.isArray(p.nationalities)?p.nationalities.map(text).filter(n=>n!==void 0).slice(0,5):[];nationalities.length>0&&(record.nationalities=nationalities);let photoDate=isoDay(response?.datePhoto);return photoDate!==void 0&&(record.photoDate=photoDate),record}function text(value){if(typeof value!="string")return;let s=value.trim();return s.length>0?s:void 0}function isoDay(value){let s=text(value);if(s===void 0)return;let iso=/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/.exec(s),fr=/^(\d{2})\/(\d{2})\/(\d{4})$/.exec(s),[y,m,d]=iso?[iso[1],iso[2],iso[3]]:fr?[fr[3],fr[2],fr[1]]:[];if(y===void 0||m===void 0||d===void 0)return;let t=new Date(Date.UTC(Number(y),Number(m)-1,Number(d)));return t.getUTCFullYear()===Number(y)&&t.getUTCMonth()===Number(m)-1&&t.getUTCDate()===Number(d)?`${y}-${m}-${d}`:void 0}var import_node_crypto=require("crypto");var SEKYRO_SIGNATURE_HEADER="x-sekyro-signature",LEGACY_SIGNATURE_HEADER="x-ibtikar-signature";function signatureFromHeaders(headers){return readHeader(headers,SEKYRO_SIGNATURE_HEADER)??readHeader(headers,LEGACY_SIGNATURE_HEADER)}function readHeader(headers,name){if(typeof headers.get=="function"){let v2=headers.get(name);return v2===null||v2===""?void 0:v2}let record=headers,key=Object.keys(record).find(k=>k.toLowerCase()===name);if(key===void 0)return;let raw=record[key],v=Array.isArray(raw)?raw[0]:raw;return v===void 0||v===""?void 0:v}var HEX64=/^[0-9a-f]{64}$/i;function verifyWebhook(rawBody,header,secret,opts={}){if(!header||!secret)throw new SekyroWebhookError("invalid_signature");let parts=header.split(",").map(part=>{let trimmed=part.trim(),eq=trimmed.indexOf("=");return eq===-1?[trimmed,""]:[trimmed.slice(0,eq).trim(),trimmed.slice(eq+1).trim()]}),tRaw=parts.find(([k])=>k==="t")?.[1],t=tRaw!==void 0&&/^\d+$/.test(tRaw)?Number(tRaw):Number.NaN,sigs=parts.filter(([k])=>k==="v1").map(([,v])=>v);if(!Number.isSafeInteger(t)||sigs.length===0)throw new SekyroWebhookError("malformed");let nowSec=Math.floor((opts.now?.()??Date.now())/1e3),tolerance=opts.toleranceSec??300;if(Math.abs(nowSec-t)>tolerance)throw new SekyroWebhookError("stale");let expected=(0,import_node_crypto.createHmac)("sha256",secret).update(`${t}.${rawBody}`).digest();if(!sigs.some(hex=>{if(!HEX64.test(hex))return!1;let got=Buffer.from(hex,"hex");return got.length===expected.length&&(0,import_node_crypto.timingSafeEqual)(got,expected)}))throw new SekyroWebhookError("invalid_signature");let parsed;try{parsed=JSON.parse(rawBody)}catch{throw new SekyroWebhookError("malformed","Signed body is not valid JSON")}if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))throw new SekyroWebhookError("malformed","Signed body is not a JSON object");return parsed}0&&(module.exports={DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER,Sekyro,SekyroApiError,SekyroConfigError,SekyroWebhookError,isFlowError,registryFromAnrpts,signatureFromHeaders,verifyWebhook});
|
package/dist/index.d.cts
CHANGED
|
@@ -212,23 +212,42 @@ interface SessionSubjectInput {
|
|
|
212
212
|
*/
|
|
213
213
|
reuse?: SubjectReuseTarget;
|
|
214
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* An identity document for {@link SubjectReuseTarget}: the document type, the
|
|
217
|
+
* issuing country (ISO 3166-1 alpha-2 or alpha-3) and its number.
|
|
218
|
+
* @public
|
|
219
|
+
*/
|
|
220
|
+
interface SubjectReuseDocument {
|
|
221
|
+
type: "national_id" | "passport" | "residence_permit";
|
|
222
|
+
issuingCountry: string;
|
|
223
|
+
number: string;
|
|
224
|
+
}
|
|
215
225
|
/**
|
|
216
226
|
* Which subject a returning-user session re-verifies — exactly ONE of the
|
|
217
|
-
* subject id, your own `externalRef` (must match a single subject)
|
|
227
|
+
* subject id, your own `externalRef` (must match a single subject), the NNI
|
|
228
|
+
* or an identity document the person verified with.
|
|
218
229
|
* @public
|
|
219
230
|
*/
|
|
220
231
|
type SubjectReuseTarget = {
|
|
221
232
|
subjectId: string;
|
|
222
233
|
externalRef?: never;
|
|
223
234
|
nni?: never;
|
|
235
|
+
document?: never;
|
|
224
236
|
} | {
|
|
225
237
|
externalRef: string;
|
|
226
238
|
subjectId?: never;
|
|
227
239
|
nni?: never;
|
|
240
|
+
document?: never;
|
|
228
241
|
} | {
|
|
229
242
|
nni: string;
|
|
230
243
|
subjectId?: never;
|
|
231
244
|
externalRef?: never;
|
|
245
|
+
document?: never;
|
|
246
|
+
} | {
|
|
247
|
+
document: SubjectReuseDocument;
|
|
248
|
+
subjectId?: never;
|
|
249
|
+
externalRef?: never;
|
|
250
|
+
nni?: never;
|
|
232
251
|
};
|
|
233
252
|
/** A document type the backend reads (kyc-docs-v2 vocabulary; `carte_identite` = identity card of any issuer). @public */
|
|
234
253
|
type ProfileDocumentType = "carte_identite" | "passport" | "residence_permit";
|
|
@@ -507,6 +526,14 @@ interface CreateSessionInput {
|
|
|
507
526
|
* values answers `400 subject_input_conflict`.
|
|
508
527
|
*/
|
|
509
528
|
subject?: SessionSubjectInput;
|
|
529
|
+
/**
|
|
530
|
+
* Your own id for the agent filming the person, for flows whose liveness
|
|
531
|
+
* capture is `assisted` (1 to 128 characters). Stored as is and echoed on
|
|
532
|
+
* the session and in webhooks.
|
|
533
|
+
*/
|
|
534
|
+
assistedBy?: {
|
|
535
|
+
externalRef: string;
|
|
536
|
+
};
|
|
510
537
|
/**
|
|
511
538
|
* Override the flow for this session only ({@link FlowOverrides}): its
|
|
512
539
|
* general settings and per-service settings, or turn a service `'off'`.
|
|
@@ -717,6 +744,8 @@ interface Session {
|
|
|
717
744
|
expiresAt: string;
|
|
718
745
|
/** ISO 8601. */
|
|
719
746
|
createdAt: string;
|
|
747
|
+
/** ISO 8601: when the session reached a terminal state; `null` while it is active. */
|
|
748
|
+
completedAt?: string | null;
|
|
720
749
|
/** End-user network context; absent when not recorded. */
|
|
721
750
|
network?: SessionNetwork;
|
|
722
751
|
/** End-user device; absent when not recorded. */
|
|
@@ -731,6 +760,10 @@ interface Session {
|
|
|
731
760
|
subjectId?: string;
|
|
732
761
|
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
733
762
|
externalRef?: string;
|
|
763
|
+
/** The agent reference sent as `assistedBy` at create, for assisted capture. */
|
|
764
|
+
assistedBy?: {
|
|
765
|
+
externalRef: string;
|
|
766
|
+
};
|
|
734
767
|
/**
|
|
735
768
|
* `true` when an identifier this session read already belongs to a
|
|
736
769
|
* different subject than `subjectId` — the subjects are never merged.
|
|
@@ -1488,4 +1521,4 @@ interface VerifyWebhookOptions {
|
|
|
1488
1521
|
*/
|
|
1489
1522
|
declare function verifyWebhook(rawBody: string, header: string | null | undefined, secret: string, opts?: VerifyWebhookOptions): WebhookEnvelope;
|
|
1490
1523
|
|
|
1491
|
-
export { type AnrptsPersonneResponse, type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeletedSubject, type DeliverOptions, type DocumentSubstitutionSettings, type EidResult, type EligibilityReason, type FetchLike, type FlowErrorDetails, type FlowErrorIssue, type FlowOverridableSettings, type FlowOverrides, type FlowRefErrorDetails, type FlowServiceSettings, type FlowSummary, type FlowWidensErrorDetails, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type PortraitReportEntry, type ProbeBindingReason, type ProbeQuality, type ProfileDocumentType, type RegistryFromAnrptsOptions, type RequestOptions, type RevokeSubjectInput, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorCode, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroFlowError, type SekyroFlowErrorCode, type SekyroFlowErrorDetailsMap, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type ServiceId, type Session, type SessionDevice, type SessionDeviceSignal, type SessionEventData, type SessionFailureReason, type SessionFlowRef, type SessionLifecycleEventData, type SessionNetwork, type SessionNetworkEvent, type SessionOutcome, type SessionPortraitLink, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type Subject, type SubjectAssurance, type SubjectDeletedEventData, type SubjectEnrolledEventData, type SubjectReferenceSource, type SubjectReuseTarget, type SubjectSession, type SubjectStatus, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, SubjectsApi, type SuppliedIdentityRecord, type VerifiedContacts, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, isFlowError, registryFromAnrpts, signatureFromHeaders, verifyWebhook };
|
|
1524
|
+
export { type AnrptsPersonneResponse, type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeletedSubject, type DeliverOptions, type DocumentSubstitutionSettings, type EidResult, type EligibilityReason, type FetchLike, type FlowErrorDetails, type FlowErrorIssue, type FlowOverridableSettings, type FlowOverrides, type FlowRefErrorDetails, type FlowServiceSettings, type FlowSummary, type FlowWidensErrorDetails, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type PortraitReportEntry, type ProbeBindingReason, type ProbeQuality, type ProfileDocumentType, type RegistryFromAnrptsOptions, type RequestOptions, type RevokeSubjectInput, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorCode, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroFlowError, type SekyroFlowErrorCode, type SekyroFlowErrorDetailsMap, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type ServiceId, type Session, type SessionDevice, type SessionDeviceSignal, type SessionEventData, type SessionFailureReason, type SessionFlowRef, type SessionLifecycleEventData, type SessionNetwork, type SessionNetworkEvent, type SessionOutcome, type SessionPortraitLink, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type Subject, type SubjectAssurance, type SubjectDeletedEventData, type SubjectEnrolledEventData, type SubjectReferenceSource, type SubjectReuseDocument, type SubjectReuseTarget, type SubjectSession, type SubjectStatus, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, SubjectsApi, type SuppliedIdentityRecord, type VerifiedContacts, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, isFlowError, registryFromAnrpts, signatureFromHeaders, verifyWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -212,23 +212,42 @@ interface SessionSubjectInput {
|
|
|
212
212
|
*/
|
|
213
213
|
reuse?: SubjectReuseTarget;
|
|
214
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* An identity document for {@link SubjectReuseTarget}: the document type, the
|
|
217
|
+
* issuing country (ISO 3166-1 alpha-2 or alpha-3) and its number.
|
|
218
|
+
* @public
|
|
219
|
+
*/
|
|
220
|
+
interface SubjectReuseDocument {
|
|
221
|
+
type: "national_id" | "passport" | "residence_permit";
|
|
222
|
+
issuingCountry: string;
|
|
223
|
+
number: string;
|
|
224
|
+
}
|
|
215
225
|
/**
|
|
216
226
|
* Which subject a returning-user session re-verifies — exactly ONE of the
|
|
217
|
-
* subject id, your own `externalRef` (must match a single subject)
|
|
227
|
+
* subject id, your own `externalRef` (must match a single subject), the NNI
|
|
228
|
+
* or an identity document the person verified with.
|
|
218
229
|
* @public
|
|
219
230
|
*/
|
|
220
231
|
type SubjectReuseTarget = {
|
|
221
232
|
subjectId: string;
|
|
222
233
|
externalRef?: never;
|
|
223
234
|
nni?: never;
|
|
235
|
+
document?: never;
|
|
224
236
|
} | {
|
|
225
237
|
externalRef: string;
|
|
226
238
|
subjectId?: never;
|
|
227
239
|
nni?: never;
|
|
240
|
+
document?: never;
|
|
228
241
|
} | {
|
|
229
242
|
nni: string;
|
|
230
243
|
subjectId?: never;
|
|
231
244
|
externalRef?: never;
|
|
245
|
+
document?: never;
|
|
246
|
+
} | {
|
|
247
|
+
document: SubjectReuseDocument;
|
|
248
|
+
subjectId?: never;
|
|
249
|
+
externalRef?: never;
|
|
250
|
+
nni?: never;
|
|
232
251
|
};
|
|
233
252
|
/** A document type the backend reads (kyc-docs-v2 vocabulary; `carte_identite` = identity card of any issuer). @public */
|
|
234
253
|
type ProfileDocumentType = "carte_identite" | "passport" | "residence_permit";
|
|
@@ -507,6 +526,14 @@ interface CreateSessionInput {
|
|
|
507
526
|
* values answers `400 subject_input_conflict`.
|
|
508
527
|
*/
|
|
509
528
|
subject?: SessionSubjectInput;
|
|
529
|
+
/**
|
|
530
|
+
* Your own id for the agent filming the person, for flows whose liveness
|
|
531
|
+
* capture is `assisted` (1 to 128 characters). Stored as is and echoed on
|
|
532
|
+
* the session and in webhooks.
|
|
533
|
+
*/
|
|
534
|
+
assistedBy?: {
|
|
535
|
+
externalRef: string;
|
|
536
|
+
};
|
|
510
537
|
/**
|
|
511
538
|
* Override the flow for this session only ({@link FlowOverrides}): its
|
|
512
539
|
* general settings and per-service settings, or turn a service `'off'`.
|
|
@@ -717,6 +744,8 @@ interface Session {
|
|
|
717
744
|
expiresAt: string;
|
|
718
745
|
/** ISO 8601. */
|
|
719
746
|
createdAt: string;
|
|
747
|
+
/** ISO 8601: when the session reached a terminal state; `null` while it is active. */
|
|
748
|
+
completedAt?: string | null;
|
|
720
749
|
/** End-user network context; absent when not recorded. */
|
|
721
750
|
network?: SessionNetwork;
|
|
722
751
|
/** End-user device; absent when not recorded. */
|
|
@@ -731,6 +760,10 @@ interface Session {
|
|
|
731
760
|
subjectId?: string;
|
|
732
761
|
/** Your own id for the person, from `subject.externalRef` at create. */
|
|
733
762
|
externalRef?: string;
|
|
763
|
+
/** The agent reference sent as `assistedBy` at create, for assisted capture. */
|
|
764
|
+
assistedBy?: {
|
|
765
|
+
externalRef: string;
|
|
766
|
+
};
|
|
734
767
|
/**
|
|
735
768
|
* `true` when an identifier this session read already belongs to a
|
|
736
769
|
* different subject than `subjectId` — the subjects are never merged.
|
|
@@ -1488,4 +1521,4 @@ interface VerifyWebhookOptions {
|
|
|
1488
1521
|
*/
|
|
1489
1522
|
declare function verifyWebhook(rawBody: string, header: string | null | undefined, secret: string, opts?: VerifyWebhookOptions): WebhookEnvelope;
|
|
1490
1523
|
|
|
1491
|
-
export { type AnrptsPersonneResponse, type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeletedSubject, type DeliverOptions, type DocumentSubstitutionSettings, type EidResult, type EligibilityReason, type FetchLike, type FlowErrorDetails, type FlowErrorIssue, type FlowOverridableSettings, type FlowOverrides, type FlowRefErrorDetails, type FlowServiceSettings, type FlowSummary, type FlowWidensErrorDetails, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type PortraitReportEntry, type ProbeBindingReason, type ProbeQuality, type ProfileDocumentType, type RegistryFromAnrptsOptions, type RequestOptions, type RevokeSubjectInput, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorCode, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroFlowError, type SekyroFlowErrorCode, type SekyroFlowErrorDetailsMap, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type ServiceId, type Session, type SessionDevice, type SessionDeviceSignal, type SessionEventData, type SessionFailureReason, type SessionFlowRef, type SessionLifecycleEventData, type SessionNetwork, type SessionNetworkEvent, type SessionOutcome, type SessionPortraitLink, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type Subject, type SubjectAssurance, type SubjectDeletedEventData, type SubjectEnrolledEventData, type SubjectReferenceSource, type SubjectReuseTarget, type SubjectSession, type SubjectStatus, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, SubjectsApi, type SuppliedIdentityRecord, type VerifiedContacts, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, isFlowError, registryFromAnrpts, signatureFromHeaders, verifyWebhook };
|
|
1524
|
+
export { type AnrptsPersonneResponse, type CheckState, type CheckType, type CreateSessionInput, type CreatedSession, DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, type DecisionReason, type DeepPartial, type DeletedSubject, type DeliverOptions, type DocumentSubstitutionSettings, type EidResult, type EligibilityReason, type FetchLike, type FlowErrorDetails, type FlowErrorIssue, type FlowOverridableSettings, type FlowOverrides, type FlowRefErrorDetails, type FlowServiceSettings, type FlowSummary, type FlowWidensErrorDetails, type IdentityMethod, LEGACY_SIGNATURE_HEADER, type Locale, type MatchReason, type PolicyFailureReason, type PortraitReportEntry, type ProbeBindingReason, type ProbeQuality, type ProfileDocumentType, type RegistryFromAnrptsOptions, type RequestOptions, type RevokeSubjectInput, SEKYRO_SIGNATURE_HEADER, Sekyro, SekyroApiError, type SekyroApiErrorCode, type SekyroApiErrorInit, type SekyroClientErrorCode, SekyroConfigError, type SekyroConfigErrorCode, type SekyroEnvironment, type SekyroFlowError, type SekyroFlowErrorCode, type SekyroFlowErrorDetailsMap, type SekyroOptions, SekyroWebhookError, type SekyroWebhookErrorCode, type ServiceId, type Session, type SessionDevice, type SessionDeviceSignal, type SessionEventData, type SessionFailureReason, type SessionFlowRef, type SessionLifecycleEventData, type SessionNetwork, type SessionNetworkEvent, type SessionOutcome, type SessionPortraitLink, type SessionReviewDecidedEventData, type SessionStatus, type SessionStep, type SessionStepCompletedEventData, type SessionSubjectInput, SessionsApi, type Subject, type SubjectAssurance, type SubjectDeletedEventData, type SubjectEnrolledEventData, type SubjectReferenceSource, type SubjectReuseDocument, type SubjectReuseTarget, type SubjectSession, type SubjectStatus, type SubjectSuspiciousActivityEventData, type SubjectUpdatedEventData, SubjectsApi, type SuppliedIdentityRecord, type VerifiedContacts, type VerifyWebhookOptions, type WebhookEnvelope, type WebhookEnvelopeOf, type WebhookEventDataMap, type WebhookEventType, isFlowError, registryFromAnrpts, signatureFromHeaders, verifyWebhook };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var WEBHOOK_MESSAGES={invalid_signature:"No v1 signature in the header matches this body and secret",stale:"Delivery timestamp is outside the tolerance window",malformed:"Signature header or body is not in the expected format"},SekyroWebhookError=class extends Error{name="SekyroWebhookError";code;constructor(code,message=WEBHOOK_MESSAGES[code]){super(message),this.code=code}},CONFIG_MESSAGES={missing_api_key:"Sekyro AI: `apiKey` is required",invalid_base_url:"Sekyro AI: `baseUrl` must be an https: URL (http: is allowed only for localhost, 127.0.0.1 or [::1])",invalid_registry_record:"Sekyro AI: the ANRPTS answer can't be used as a registry record"},SekyroConfigError=class extends TypeError{name="SekyroConfigError";code;constructor(code,message=CONFIG_MESSAGES[code]){super(message),this.code=code}},SekyroApiError=class extends Error{name="SekyroApiError";status;code;requestId;details;retryable;constructor(init){super(init.message,init.cause===void 0?void 0:{cause:init.cause}),this.status=init.status,this.code=init.code,this.requestId=init.requestId,this.details=init.details,this.retryable=isRetryable(init.status,init.code)}},FLOW_ERROR_CODES=new Set(["flow_not_found","flow_not_published","flow_archived","override_invalid","override_widens_flow","reuse_disabled","choice_not_found","choice_locked","choice_option_unavailable"]),FLOW_REF_CODES=new Set(["flow_not_published","flow_archived","reuse_disabled"]),isRecord=x=>typeof x=="object"&&x!==null&&!Array.isArray(x),isStringArray=x=>Array.isArray(x)&&x.every(s=>typeof s=="string");function isIssue(x){return isRecord(x)&&typeof x.code=="string"&&typeof x.message=="string"}function hasFlowDetails(code,details){if(!isRecord(details)||!Array.isArray(details.issues)||!details.issues.every(isIssue))return!1;if(code==="override_widens_flow")return isStringArray(details.fields);if(FLOW_REF_CODES.has(code)){let flow=details.flow;return isRecord(flow)&&typeof flow.id=="string"&&typeof flow.slug=="string"}return!0}function isFlowError(err,...codes){return!(err instanceof SekyroApiError)||!FLOW_ERROR_CODES.has(err.code)||codes.length>0&&!codes.includes(err.code)?!1:hasFlowDetails(err.code,err.details)}function isRetryable(status,code){return code==="network"||code==="timeout"||code==="idempotency_in_progress"||status===429?!0:status>=500&&status<=599}var SDK_VERSION="0.1.0-rc.5";var USER_AGENT=`@sekyro/node/${SDK_VERSION}`,DEFAULT_BASE_URL="https://api.sekyro.ai/api/v2",DEFAULT_TIMEOUT_MS=3e4;function isSuccessEnvelope(value){return typeof value=="object"&&value!==null&&value.success===!0&&"data"in value}function isErrorEnvelope(value){if(typeof value!="object"||value===null)return!1;let v=value;if(v.status!=="error"||typeof v.error!="object"||v.error===null)return!1;let e=v.error;return typeof e.code=="string"&&typeof e.message=="string"}function isAbortLike(err){if(typeof err!="object"||err===null)return!1;let name=err.name;return name==="TimeoutError"||name==="AbortError"}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function assertSafeBaseUrl(baseUrl){let url;try{url=new URL(baseUrl)}catch{throw new SekyroConfigError("invalid_base_url")}if(url.protocol!=="https:"&&!(url.protocol==="http:"&&LOOPBACK_HOSTS.has(url.hostname)))throw new SekyroConfigError("invalid_base_url")}var Transport=class{apiKey;baseUrl;timeoutMs;fetchImpl;constructor(opts){let baseUrl=(opts.baseUrl??DEFAULT_BASE_URL).replace(/\/+$/,"");assertSafeBaseUrl(baseUrl),this.apiKey=opts.apiKey,this.baseUrl=baseUrl,this.timeoutMs=opts.timeoutMs??DEFAULT_TIMEOUT_MS,this.fetchImpl=opts.fetch??globalThis.fetch}async call(method,path,body,idempotencyKey){let headers={authorization:`Bearer ${this.apiKey}`,accept:"application/json","user-agent":USER_AGENT};body!==void 0&&(headers["content-type"]="application/json"),idempotencyKey!==void 0&&(headers["x-idempotency-key"]=idempotencyKey);let init={method,headers,signal:AbortSignal.timeout(this.timeoutMs)};body!==void 0&&(init.body=JSON.stringify(body));let res;try{res=await this.fetchImpl(`${this.baseUrl}${path}`,init)}catch(err){throw isAbortLike(err)?new SekyroApiError({status:0,code:"timeout",message:`Request timed out after ${this.timeoutMs}ms`,cause:err}):new SekyroApiError({status:0,code:"network",message:`Network error: ${err instanceof Error?err.message:String(err)}`,cause:err})}let text2=await res.text(),parsed,parseError;try{parsed=text2.length>0?JSON.parse(text2):void 0}catch(err){parseError=err}if(!res.ok){if(isErrorEnvelope(parsed)){let init2={status:res.status,code:parsed.error.code,message:parsed.error.message};throw parsed.error.request_id!==void 0&&(init2.requestId=parsed.error.request_id),parsed.error.details!==void 0&&(init2.details=parsed.error.details),new SekyroApiError(init2)}throw new SekyroApiError({status:res.status,code:"http_error",message:`HTTP ${res.status}${res.statusText?` ${res.statusText}`:""}`})}if(!isSuccessEnvelope(parsed))throw new SekyroApiError({status:res.status,code:"malformed_response",message:"Response is not a `{ success: true, data }` envelope",cause:parseError});return parsed.data}},SessionsApi=class{constructor(call){this.call=call}call;async create(input={},opts={}){let wire=await this.call("POST","/sessions",input,opts.idempotencyKey);return{id:wire.id,status:wire.status,clientToken:wire.client_token,hostedUrl:wire.hosted_url,...wire.flow!==void 0?{flow:wire.flow}:{},steps:wire.steps,expiresAt:wire.expiresAt}}async selectMethod(id,method){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.selectMethod: `id` must be a non-empty string");return this.call("POST",`/sessions/${encodeURIComponent(id)}/method`,{method})}async get(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.get: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}`)}async portrait(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.portrait: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}/portrait?format=url`)}};function assertId(method,id){if(typeof id!="string"||id.length===0)throw new TypeError(`subjects.${method}: \`id\` must be a non-empty string`)}var SubjectsApi=class{constructor(call){this.call=call}call;async get(id){return assertId("get",id),this.call("GET",`/subjects/${encodeURIComponent(id)}`)}async list(query){if(typeof query?.externalRef!="string"||query.externalRef.length===0)throw new TypeError("subjects.list: `externalRef` must be a non-empty string");let qs=new URLSearchParams({externalRef:query.externalRef});return this.call("GET",`/subjects?${qs.toString()}`)}async revoke(id,input={},opts={}){return assertId("revoke",id),this.call("POST",`/subjects/${encodeURIComponent(id)}/revoke`,input,opts.idempotencyKey)}async delete(id){return assertId("delete",id),this.call("DELETE",`/subjects/${encodeURIComponent(id)}`)}},Sekyro=class{sessions;subjects;#transport;constructor(opts){if(typeof opts?.apiKey!="string"||opts.apiKey.length===0)throw new SekyroConfigError("missing_api_key");let transport=new Transport(opts);this.#transport=transport,this.sessions=new SessionsApi(transport.call.bind(transport)),this.subjects=new SubjectsApi(transport.call.bind(transport))}async listFlows(){return this.#transport.call("GET","/flows")}};function registryFromAnrpts(response,options){let p=response?.personne??{},required=(field,value)=>{let s=text(value);if(s===void 0)throw new SekyroConfigError("invalid_registry_record",`Sekyro AI: the ANRPTS answer has no usable \`${field}\``);return s},birthDate=isoDay(p.dateNaissance);if(birthDate===void 0)throw new SekyroConfigError("invalid_registry_record","Sekyro AI: the ANRPTS answer has no usable `personne.dateNaissance`");let photo=required("photo",response?.photo).replace(/\s+/g,""),fetchedAt=new Date(options?.fetchedAt??Number.NaN);if(Number.isNaN(fetchedAt.getTime()))throw new SekyroConfigError("invalid_registry_record","Sekyro AI: `fetchedAt` (when your system received the ANRPTS answer) is missing or not a valid date");let record={nni:required("personne.nni",p.nni),firstNameFr:required("personne.prenomFr",p.prenomFr),lastNameFr:required("personne.patronymeFr",p.patronymeFr),firstNameAr:required("personne.prenomAr",p.prenomAr),lastNameAr:required("personne.patronymeAr",p.patronymeAr),birthDate,photo,fetchedAt:fetchedAt.toISOString()},optional=[["fatherNameFr",p.perePrenomFr],["fatherNameAr",p.perePrenomAr],["birthPlaceFr",p.lieuNaissanceFr],["birthPlaceAr",p.lieuNaissanceAr]];for(let[key,value]of optional){let s=text(value);s!==void 0&&(record[key]=s)}let sex=text(p.sexeCode)?.toUpperCase();(sex==="M"||sex==="F")&&(record.sex=sex);let nationalities=Array.isArray(p.nationalities)?p.nationalities.map(text).filter(n=>n!==void 0).slice(0,5):[];nationalities.length>0&&(record.nationalities=nationalities);let photoDate=isoDay(response?.datePhoto);return photoDate!==void 0&&(record.photoDate=photoDate),record}function text(value){if(typeof value!="string")return;let s=value.trim();return s.length>0?s:void 0}function isoDay(value){let s=text(value);if(s===void 0)return;let iso=/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/.exec(s),fr=/^(\d{2})\/(\d{2})\/(\d{4})$/.exec(s),[y,m,d]=iso?[iso[1],iso[2],iso[3]]:fr?[fr[3],fr[2],fr[1]]:[];if(y===void 0||m===void 0||d===void 0)return;let t=new Date(Date.UTC(Number(y),Number(m)-1,Number(d)));return t.getUTCFullYear()===Number(y)&&t.getUTCMonth()===Number(m)-1&&t.getUTCDate()===Number(d)?`${y}-${m}-${d}`:void 0}import{createHmac,timingSafeEqual}from"crypto";var SEKYRO_SIGNATURE_HEADER="x-sekyro-signature",LEGACY_SIGNATURE_HEADER="x-ibtikar-signature";function signatureFromHeaders(headers){return readHeader(headers,SEKYRO_SIGNATURE_HEADER)??readHeader(headers,LEGACY_SIGNATURE_HEADER)}function readHeader(headers,name){if(typeof headers.get=="function"){let v2=headers.get(name);return v2===null||v2===""?void 0:v2}let record=headers,key=Object.keys(record).find(k=>k.toLowerCase()===name);if(key===void 0)return;let raw=record[key],v=Array.isArray(raw)?raw[0]:raw;return v===void 0||v===""?void 0:v}var HEX64=/^[0-9a-f]{64}$/i;function verifyWebhook(rawBody,header,secret,opts={}){if(!header||!secret)throw new SekyroWebhookError("invalid_signature");let parts=header.split(",").map(part=>{let trimmed=part.trim(),eq=trimmed.indexOf("=");return eq===-1?[trimmed,""]:[trimmed.slice(0,eq).trim(),trimmed.slice(eq+1).trim()]}),tRaw=parts.find(([k])=>k==="t")?.[1],t=tRaw!==void 0&&/^\d+$/.test(tRaw)?Number(tRaw):Number.NaN,sigs=parts.filter(([k])=>k==="v1").map(([,v])=>v);if(!Number.isSafeInteger(t)||sigs.length===0)throw new SekyroWebhookError("malformed");let nowSec=Math.floor((opts.now?.()??Date.now())/1e3),tolerance=opts.toleranceSec??300;if(Math.abs(nowSec-t)>tolerance)throw new SekyroWebhookError("stale");let expected=createHmac("sha256",secret).update(`${t}.${rawBody}`).digest();if(!sigs.some(hex=>{if(!HEX64.test(hex))return!1;let got=Buffer.from(hex,"hex");return got.length===expected.length&&timingSafeEqual(got,expected)}))throw new SekyroWebhookError("invalid_signature");let parsed;try{parsed=JSON.parse(rawBody)}catch{throw new SekyroWebhookError("malformed","Signed body is not valid JSON")}if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))throw new SekyroWebhookError("malformed","Signed body is not a JSON object");return parsed}export{DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER,Sekyro,SekyroApiError,SekyroConfigError,SekyroWebhookError,isFlowError,registryFromAnrpts,signatureFromHeaders,verifyWebhook};
|
|
1
|
+
var WEBHOOK_MESSAGES={invalid_signature:"No v1 signature in the header matches this body and secret",stale:"Delivery timestamp is outside the tolerance window",malformed:"Signature header or body is not in the expected format"},SekyroWebhookError=class extends Error{name="SekyroWebhookError";code;constructor(code,message=WEBHOOK_MESSAGES[code]){super(message),this.code=code}},CONFIG_MESSAGES={missing_api_key:"Sekyro AI: `apiKey` is required",invalid_base_url:"Sekyro AI: `baseUrl` must be an https: URL (http: is allowed only for localhost, 127.0.0.1 or [::1])",invalid_registry_record:"Sekyro AI: the ANRPTS answer can't be used as a registry record"},SekyroConfigError=class extends TypeError{name="SekyroConfigError";code;constructor(code,message=CONFIG_MESSAGES[code]){super(message),this.code=code}},SekyroApiError=class extends Error{name="SekyroApiError";status;code;requestId;details;retryable;constructor(init){super(init.message,init.cause===void 0?void 0:{cause:init.cause}),this.status=init.status,this.code=init.code,this.requestId=init.requestId,this.details=init.details,this.retryable=isRetryable(init.status,init.code)}},FLOW_ERROR_CODES=new Set(["flow_not_found","flow_not_published","flow_archived","override_invalid","override_widens_flow","reuse_disabled","choice_not_found","choice_locked","choice_option_unavailable"]),FLOW_REF_CODES=new Set(["flow_not_published","flow_archived","reuse_disabled"]),isRecord=x=>typeof x=="object"&&x!==null&&!Array.isArray(x),isStringArray=x=>Array.isArray(x)&&x.every(s=>typeof s=="string");function isIssue(x){return isRecord(x)&&typeof x.code=="string"&&typeof x.message=="string"}function hasFlowDetails(code,details){if(!isRecord(details)||!Array.isArray(details.issues)||!details.issues.every(isIssue))return!1;if(code==="override_widens_flow")return isStringArray(details.fields);if(FLOW_REF_CODES.has(code)){let flow=details.flow;return isRecord(flow)&&typeof flow.id=="string"&&typeof flow.slug=="string"}return!0}function isFlowError(err,...codes){return!(err instanceof SekyroApiError)||!FLOW_ERROR_CODES.has(err.code)||codes.length>0&&!codes.includes(err.code)?!1:hasFlowDetails(err.code,err.details)}function isRetryable(status,code){return code==="network"||code==="timeout"||code==="idempotency_in_progress"||status===429?!0:status>=500&&status<=599}var SDK_VERSION="0.1.0-rc.6";var USER_AGENT=`@sekyro/node/${SDK_VERSION}`,DEFAULT_BASE_URL="https://api.sekyro.ai/api/v2",DEFAULT_TIMEOUT_MS=3e4;function isSuccessEnvelope(value){return typeof value=="object"&&value!==null&&value.success===!0&&"data"in value}function isErrorEnvelope(value){if(typeof value!="object"||value===null)return!1;let v=value;if(v.status!=="error"||typeof v.error!="object"||v.error===null)return!1;let e=v.error;return typeof e.code=="string"&&typeof e.message=="string"}function isAbortLike(err){if(typeof err!="object"||err===null)return!1;let name=err.name;return name==="TimeoutError"||name==="AbortError"}var LOOPBACK_HOSTS=new Set(["localhost","127.0.0.1","[::1]"]);function assertSafeBaseUrl(baseUrl){let url;try{url=new URL(baseUrl)}catch{throw new SekyroConfigError("invalid_base_url")}if(url.protocol!=="https:"&&!(url.protocol==="http:"&&LOOPBACK_HOSTS.has(url.hostname)))throw new SekyroConfigError("invalid_base_url")}var Transport=class{apiKey;baseUrl;timeoutMs;fetchImpl;constructor(opts){let baseUrl=(opts.baseUrl??DEFAULT_BASE_URL).replace(/\/+$/,"");assertSafeBaseUrl(baseUrl),this.apiKey=opts.apiKey,this.baseUrl=baseUrl,this.timeoutMs=opts.timeoutMs??DEFAULT_TIMEOUT_MS,this.fetchImpl=opts.fetch??globalThis.fetch}async call(method,path,body,idempotencyKey){let headers={authorization:`Bearer ${this.apiKey}`,accept:"application/json","user-agent":USER_AGENT};body!==void 0&&(headers["content-type"]="application/json"),idempotencyKey!==void 0&&(headers["x-idempotency-key"]=idempotencyKey);let init={method,headers,signal:AbortSignal.timeout(this.timeoutMs)};body!==void 0&&(init.body=JSON.stringify(body));let res;try{res=await this.fetchImpl(`${this.baseUrl}${path}`,init)}catch(err){throw isAbortLike(err)?new SekyroApiError({status:0,code:"timeout",message:`Request timed out after ${this.timeoutMs}ms`,cause:err}):new SekyroApiError({status:0,code:"network",message:`Network error: ${err instanceof Error?err.message:String(err)}`,cause:err})}let text2=await res.text(),parsed,parseError;try{parsed=text2.length>0?JSON.parse(text2):void 0}catch(err){parseError=err}if(!res.ok){if(isErrorEnvelope(parsed)){let init2={status:res.status,code:parsed.error.code,message:parsed.error.message};throw parsed.error.request_id!==void 0&&(init2.requestId=parsed.error.request_id),parsed.error.details!==void 0&&(init2.details=parsed.error.details),new SekyroApiError(init2)}throw new SekyroApiError({status:res.status,code:"http_error",message:`HTTP ${res.status}${res.statusText?` ${res.statusText}`:""}`})}if(!isSuccessEnvelope(parsed))throw new SekyroApiError({status:res.status,code:"malformed_response",message:"Response is not a `{ success: true, data }` envelope",cause:parseError});return parsed.data}},SessionsApi=class{constructor(call){this.call=call}call;async create(input={},opts={}){let wire=await this.call("POST","/sessions",input,opts.idempotencyKey);return{id:wire.id,status:wire.status,clientToken:wire.client_token,hostedUrl:wire.hosted_url,...wire.flow!==void 0?{flow:wire.flow}:{},steps:wire.steps,expiresAt:wire.expiresAt}}async selectMethod(id,method){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.selectMethod: `id` must be a non-empty string");return this.call("POST",`/sessions/${encodeURIComponent(id)}/method`,{method})}async get(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.get: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}`)}async portrait(id){if(typeof id!="string"||id.length===0)throw new TypeError("sessions.portrait: `id` must be a non-empty string");return this.call("GET",`/sessions/${encodeURIComponent(id)}/portrait?format=url`)}};function assertId(method,id){if(typeof id!="string"||id.length===0)throw new TypeError(`subjects.${method}: \`id\` must be a non-empty string`)}var SubjectsApi=class{constructor(call){this.call=call}call;async get(id){return assertId("get",id),this.call("GET",`/subjects/${encodeURIComponent(id)}`)}async list(query){if(typeof query?.externalRef!="string"||query.externalRef.length===0)throw new TypeError("subjects.list: `externalRef` must be a non-empty string");let qs=new URLSearchParams({externalRef:query.externalRef});return this.call("GET",`/subjects?${qs.toString()}`)}async revoke(id,input={},opts={}){return assertId("revoke",id),this.call("POST",`/subjects/${encodeURIComponent(id)}/revoke`,input,opts.idempotencyKey)}async delete(id){return assertId("delete",id),this.call("DELETE",`/subjects/${encodeURIComponent(id)}`)}},Sekyro=class{sessions;subjects;#transport;constructor(opts){if(typeof opts?.apiKey!="string"||opts.apiKey.length===0)throw new SekyroConfigError("missing_api_key");let transport=new Transport(opts);this.#transport=transport,this.sessions=new SessionsApi(transport.call.bind(transport)),this.subjects=new SubjectsApi(transport.call.bind(transport))}async listFlows(){return this.#transport.call("GET","/flows")}};function registryFromAnrpts(response,options){let p=response?.personne??{},required=(field,value)=>{let s=text(value);if(s===void 0)throw new SekyroConfigError("invalid_registry_record",`Sekyro AI: the ANRPTS answer has no usable \`${field}\``);return s},birthDate=isoDay(p.dateNaissance);if(birthDate===void 0)throw new SekyroConfigError("invalid_registry_record","Sekyro AI: the ANRPTS answer has no usable `personne.dateNaissance`");let photo=required("photo",response?.photo).replace(/\s+/g,""),fetchedAt=new Date(options?.fetchedAt??Number.NaN);if(Number.isNaN(fetchedAt.getTime()))throw new SekyroConfigError("invalid_registry_record","Sekyro AI: `fetchedAt` (when your system received the ANRPTS answer) is missing or not a valid date");let record={nni:required("personne.nni",p.nni),firstNameFr:required("personne.prenomFr",p.prenomFr),lastNameFr:required("personne.patronymeFr",p.patronymeFr),firstNameAr:required("personne.prenomAr",p.prenomAr),lastNameAr:required("personne.patronymeAr",p.patronymeAr),birthDate,photo,fetchedAt:fetchedAt.toISOString()},optional=[["fatherNameFr",p.perePrenomFr],["fatherNameAr",p.perePrenomAr],["birthPlaceFr",p.lieuNaissanceFr],["birthPlaceAr",p.lieuNaissanceAr]];for(let[key,value]of optional){let s=text(value);s!==void 0&&(record[key]=s)}let sex=text(p.sexeCode)?.toUpperCase();(sex==="M"||sex==="F")&&(record.sex=sex);let nationalities=Array.isArray(p.nationalities)?p.nationalities.map(text).filter(n=>n!==void 0).slice(0,5):[];nationalities.length>0&&(record.nationalities=nationalities);let photoDate=isoDay(response?.datePhoto);return photoDate!==void 0&&(record.photoDate=photoDate),record}function text(value){if(typeof value!="string")return;let s=value.trim();return s.length>0?s:void 0}function isoDay(value){let s=text(value);if(s===void 0)return;let iso=/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/.exec(s),fr=/^(\d{2})\/(\d{2})\/(\d{4})$/.exec(s),[y,m,d]=iso?[iso[1],iso[2],iso[3]]:fr?[fr[3],fr[2],fr[1]]:[];if(y===void 0||m===void 0||d===void 0)return;let t=new Date(Date.UTC(Number(y),Number(m)-1,Number(d)));return t.getUTCFullYear()===Number(y)&&t.getUTCMonth()===Number(m)-1&&t.getUTCDate()===Number(d)?`${y}-${m}-${d}`:void 0}import{createHmac,timingSafeEqual}from"crypto";var SEKYRO_SIGNATURE_HEADER="x-sekyro-signature",LEGACY_SIGNATURE_HEADER="x-ibtikar-signature";function signatureFromHeaders(headers){return readHeader(headers,SEKYRO_SIGNATURE_HEADER)??readHeader(headers,LEGACY_SIGNATURE_HEADER)}function readHeader(headers,name){if(typeof headers.get=="function"){let v2=headers.get(name);return v2===null||v2===""?void 0:v2}let record=headers,key=Object.keys(record).find(k=>k.toLowerCase()===name);if(key===void 0)return;let raw=record[key],v=Array.isArray(raw)?raw[0]:raw;return v===void 0||v===""?void 0:v}var HEX64=/^[0-9a-f]{64}$/i;function verifyWebhook(rawBody,header,secret,opts={}){if(!header||!secret)throw new SekyroWebhookError("invalid_signature");let parts=header.split(",").map(part=>{let trimmed=part.trim(),eq=trimmed.indexOf("=");return eq===-1?[trimmed,""]:[trimmed.slice(0,eq).trim(),trimmed.slice(eq+1).trim()]}),tRaw=parts.find(([k])=>k==="t")?.[1],t=tRaw!==void 0&&/^\d+$/.test(tRaw)?Number(tRaw):Number.NaN,sigs=parts.filter(([k])=>k==="v1").map(([,v])=>v);if(!Number.isSafeInteger(t)||sigs.length===0)throw new SekyroWebhookError("malformed");let nowSec=Math.floor((opts.now?.()??Date.now())/1e3),tolerance=opts.toleranceSec??300;if(Math.abs(nowSec-t)>tolerance)throw new SekyroWebhookError("stale");let expected=createHmac("sha256",secret).update(`${t}.${rawBody}`).digest();if(!sigs.some(hex=>{if(!HEX64.test(hex))return!1;let got=Buffer.from(hex,"hex");return got.length===expected.length&&timingSafeEqual(got,expected)}))throw new SekyroWebhookError("invalid_signature");let parsed;try{parsed=JSON.parse(rawBody)}catch{throw new SekyroWebhookError("malformed","Signed body is not valid JSON")}if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))throw new SekyroWebhookError("malformed","Signed body is not a JSON object");return parsed}export{DEFAULT_BASE_URL,DEFAULT_TIMEOUT_MS,LEGACY_SIGNATURE_HEADER,SEKYRO_SIGNATURE_HEADER,Sekyro,SekyroApiError,SekyroConfigError,SekyroWebhookError,isFlowError,registryFromAnrpts,signatureFromHeaders,verifyWebhook};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sekyro/node",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.6",
|
|
4
4
|
"description": "Sekyro AI server SDK for Node.js — create and read verification sessions, verify signed webhooks. Zero runtime dependencies.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
package/sbom.cdx.json
CHANGED
|
@@ -97,8 +97,8 @@
|
|
|
97
97
|
"type": "application",
|
|
98
98
|
"name": "node",
|
|
99
99
|
"group": "@sekyro",
|
|
100
|
-
"version": "0.1.0-rc.
|
|
101
|
-
"bom-ref": "@sekyro/node@0.1.0-rc.
|
|
100
|
+
"version": "0.1.0-rc.6",
|
|
101
|
+
"bom-ref": "@sekyro/node@0.1.0-rc.6",
|
|
102
102
|
"description": "Sekyro AI server SDK for Node.js — create and read verification sessions, verify signed webhooks. Zero runtime dependencies.",
|
|
103
103
|
"licenses": [
|
|
104
104
|
{
|
|
@@ -108,7 +108,7 @@
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
],
|
|
111
|
-
"purl": "pkg:npm/%40sekyro/node@0.1.0-rc.
|
|
111
|
+
"purl": "pkg:npm/%40sekyro/node@0.1.0-rc.6?vcs_url=git%2Bhttps%3A%2F%2Fgithub.com%2FIBTIKAR-Technologies%2Fibtikar-identity.git%23packages%2Fsekyro-node",
|
|
112
112
|
"externalReferences": [
|
|
113
113
|
{
|
|
114
114
|
"url": "https://github.com/IBTIKAR-Technologies/ibtikar-identity/issues",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"components": [],
|
|
148
148
|
"dependencies": [
|
|
149
149
|
{
|
|
150
|
-
"ref": "@sekyro/node@0.1.0-rc.
|
|
150
|
+
"ref": "@sekyro/node@0.1.0-rc.6"
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
}
|