@sekyro/web 0.1.0-rc.1 → 0.1.0-rc.2

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.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as CaptureChannel, a as CaptureError, b as CaptureErrorKind, c as CaptureState, d as CapturedArtifacts, D as DEFAULT_API_ORIGIN, G as GateHint, e as GateUpdate, L as LivenessCaptureEvents, f as LivenessCaptureHandle, g as LivenessCaptureOptions, R as ReasonCode, S as SdkFailureReason, V as Verification, h as VerificationEvents, i as VerificationLocale, j as VerificationOptions, k as VerificationResult, l as VerificationStatus, m as createLivenessCapture, n as createVerification } from './create-verification--ldwakXV.cjs';
1
+ export { C as CaptureChannel, a as CaptureError, b as CaptureErrorKind, c as CaptureState, d as CapturedArtifacts, D as DEFAULT_API_ORIGIN, G as GateHint, e as GateUpdate, L as LivenessCaptureEvents, f as LivenessCaptureHandle, g as LivenessCaptureOptions, R as ReasonCode, S as SdkFailureReason, V as Verification, h as VerificationEvents, i as VerificationLocale, j as VerificationOptions, k as VerificationResult, l as VerificationStatus, m as createLivenessCapture, n as createVerification } from './create-verification-EnZ13uY4.cjs';
2
2
  export { OpenHostedOptions, PopupBlocked, PopupHandle, SEKYRO_EVENTS, SekyroEvent, SekyroEventName, openHosted } from './popup/index.cjs';
3
3
  export { HostedApiError, KNOWN_CODES, KnownCode, isKnownCode } from './client/index.cjs';
4
4
  export { C as CheckReason, a as CheckState, b as CheckType, D as DocReason, F as FaceMatchReason, H as HostedOtpView, c as HostedSessionView, d as HostedStepView, L as LivenessReason, P as PhoneOtpReason, e as PopulationReason, S as SessionOutcome, f as SessionStatus } from './hosted-client-BpvBqu9f.cjs';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as CaptureChannel, a as CaptureError, b as CaptureErrorKind, c as CaptureState, d as CapturedArtifacts, D as DEFAULT_API_ORIGIN, G as GateHint, e as GateUpdate, L as LivenessCaptureEvents, f as LivenessCaptureHandle, g as LivenessCaptureOptions, R as ReasonCode, S as SdkFailureReason, V as Verification, h as VerificationEvents, i as VerificationLocale, j as VerificationOptions, k as VerificationResult, l as VerificationStatus, m as createLivenessCapture, n as createVerification } from './create-verification-BlAPWeW5.js';
1
+ export { C as CaptureChannel, a as CaptureError, b as CaptureErrorKind, c as CaptureState, d as CapturedArtifacts, D as DEFAULT_API_ORIGIN, G as GateHint, e as GateUpdate, L as LivenessCaptureEvents, f as LivenessCaptureHandle, g as LivenessCaptureOptions, R as ReasonCode, S as SdkFailureReason, V as Verification, h as VerificationEvents, i as VerificationLocale, j as VerificationOptions, k as VerificationResult, l as VerificationStatus, m as createLivenessCapture, n as createVerification } from './create-verification-CjLnJ0w6.js';
2
2
  export { OpenHostedOptions, PopupBlocked, PopupHandle, SEKYRO_EVENTS, SekyroEvent, SekyroEventName, openHosted } from './popup/index.js';
3
3
  export { HostedApiError, KNOWN_CODES, KnownCode, isKnownCode } from './client/index.js';
4
4
  export { C as CheckReason, a as CheckState, b as CheckType, D as DocReason, F as FaceMatchReason, H as HostedOtpView, c as HostedSessionView, d as HostedStepView, L as LivenessReason, P as PhoneOtpReason, e as PopulationReason, S as SessionOutcome, f as SessionStatus } from './hosted-client-BpvBqu9f.js';
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  DEFAULT_API_ORIGIN,
7
7
  createLivenessCapture,
8
8
  createVerification
9
- } from "./chunk-NU4YOLCN.js";
9
+ } from "./chunk-BPYVZUJA.js";
10
10
  import "./chunk-LOTAJDRE.js";
11
11
  import {
12
12
  HostedApiError,
@@ -3593,6 +3593,7 @@ var KEYFRAME_MIME = "image/jpeg";
3593
3593
  var TRANSPORT_REPLAY_ATTEMPTS = 2;
3594
3594
  var TRANSPORT_REPLAY_DELAY_MS = 1e3;
3595
3595
  var MAX_RETRY_AFTER_MS = 1e4;
3596
+ var RESYNC_REENTRY_MAX = 3;
3596
3597
  var TRANSPORT_CODES = /* @__PURE__ */ new Set([
3597
3598
  "network_error",
3598
3599
  "timeout",
@@ -3653,6 +3654,7 @@ async function runSubmission(rt, executor, hooks = {}) {
3653
3654
  }
3654
3655
  }
3655
3656
  }
3657
+ var LIVENESS_CHAINABLE = /* @__PURE__ */ new Set(["passed", "review", "processing", "skipped"]);
3656
3658
  async function runLivenessFlow(deps) {
3657
3659
  const { artifacts } = deps;
3658
3660
  const clip = artifacts.clip;
@@ -3660,68 +3662,88 @@ async function runLivenessFlow(deps) {
3660
3662
  if (artifacts.degraded === "NO_RECORDER" || clip === void 0 || !CLIP_MIME_ALLOWLIST.includes(bareMime)) {
3661
3663
  return { kind: "unavailable", reason: "no_recorder" };
3662
3664
  }
3663
- try {
3664
- const livenessWasExecutable = isExecutable(stepOf(deps.getView(), "liveness"));
3665
- if (livenessWasExecutable) {
3666
- let clipKey = null;
3667
- let attestation = null;
3668
- const response = await runSubmission(
3669
- deps,
3670
- async (client, idempotencyKey) => {
3671
- if (clipKey === null) {
3672
- deps.onPhase("uploading");
3673
- const presigned = await client.presign("clip", bareMime, clip.size);
3674
- await client.uploadToSpaces(presigned.uploadUrl, clip, bareMime);
3675
- clipKey = (await client.completeMedia(presigned.key)).key;
3676
- }
3677
- if (attestation === null) {
3678
- try {
3679
- attestation = await deps.getAttestation();
3680
- } catch (err) {
3681
- throw new AttestationError(err instanceof Error ? err.message : String(err));
3682
- }
3683
- }
3684
- deps.onPhase("checking");
3685
- return client.submitCheck(
3686
- "liveness",
3687
- { clipKey, attestation, captureChannel: artifacts.captureChannel },
3688
- { idempotencyKey }
3689
- );
3690
- },
3691
- {
3692
- onAttestationInvalid: () => {
3693
- attestation = null;
3694
- }
3695
- }
3696
- );
3697
- if (deps.isCancelled()) return { kind: "cancelled" };
3698
- deps.applySubmit(response, "liveness");
3699
- }
3665
+ const submitLiveness = buildLivenessSubmit(deps, clip, bareMime);
3666
+ const submitFaceMatch = buildFaceMatchSubmit(deps, artifacts.keyframe);
3667
+ let livenessSubmitted = false;
3668
+ let faceMatchSubmitted = false;
3669
+ let livenessChainable = true;
3670
+ let resyncs = 0;
3671
+ for (; ; ) {
3672
+ if (deps.isCancelled()) return { kind: "cancelled" };
3700
3673
  const view = deps.getView();
3701
- const liveness = stepOf(view, "liveness");
3702
- const livenessOk = !livenessWasExecutable || liveness === void 0 || liveness.state === "passed" || liveness.state === "review" || liveness.state === "processing" || liveness.state === "skipped";
3703
- if (!isTerminalView(view) && livenessOk && isExecutable(stepOf(view, "face_match"))) {
3704
- const keyframe = artifacts.keyframe;
3705
- let imageKey = null;
3706
- const response = await runSubmission(deps, async (client, idempotencyKey) => {
3707
- if (imageKey === null) {
3708
- deps.onPhase("uploading");
3709
- const presigned = await client.presign("image", KEYFRAME_MIME, keyframe.size);
3710
- await client.uploadToSpaces(presigned.uploadUrl, keyframe, KEYFRAME_MIME);
3711
- imageKey = (await client.completeMedia(presigned.key)).key;
3712
- }
3713
- deps.onPhase("checking");
3714
- return client.submitCheck("face_match", { imageKey }, { idempotencyKey });
3715
- });
3674
+ if (isTerminalView(view)) return { kind: "settled" };
3675
+ const frontier = frontierStep(view)?.checkType;
3676
+ const next = frontier === "liveness" && !livenessSubmitted ? "liveness" : frontier === "face_match" && !faceMatchSubmitted && livenessChainable ? "face_match" : null;
3677
+ if (next === null) return { kind: "settled" };
3678
+ try {
3679
+ if (next === "liveness") {
3680
+ livenessSubmitted = true;
3681
+ const response = await submitLiveness();
3682
+ if (deps.isCancelled()) return { kind: "cancelled" };
3683
+ deps.applySubmit(response, "liveness");
3684
+ const state = stepOf(deps.getView(), "liveness")?.state;
3685
+ livenessChainable = state === void 0 || LIVENESS_CHAINABLE.has(state);
3686
+ } else {
3687
+ faceMatchSubmitted = true;
3688
+ const response = await submitFaceMatch();
3689
+ if (deps.isCancelled()) return { kind: "cancelled" };
3690
+ deps.applySubmit(response, "face_match");
3691
+ }
3692
+ } catch (err) {
3716
3693
  if (deps.isCancelled()) return { kind: "cancelled" };
3717
- deps.applySubmit(response, "face_match");
3694
+ const outcome = classifyFailure(err);
3695
+ if (outcome.kind !== "resync" || resyncs >= RESYNC_REENTRY_MAX) return outcome;
3696
+ resyncs += 1;
3697
+ await deps.refreshView();
3718
3698
  }
3719
- return { kind: "settled" };
3720
- } catch (err) {
3721
- if (deps.isCancelled()) return { kind: "cancelled" };
3722
- return classifyFailure(err);
3723
3699
  }
3724
3700
  }
3701
+ function buildLivenessSubmit(deps, clip, bareMime) {
3702
+ let clipKey = null;
3703
+ let attestation = null;
3704
+ return () => runSubmission(
3705
+ deps,
3706
+ async (client, idempotencyKey) => {
3707
+ if (clipKey === null) {
3708
+ deps.onPhase("uploading");
3709
+ const presigned = await client.presign("clip", bareMime, clip.size);
3710
+ await client.uploadToSpaces(presigned.uploadUrl, clip, bareMime);
3711
+ clipKey = (await client.completeMedia(presigned.key)).key;
3712
+ }
3713
+ if (attestation === null) {
3714
+ try {
3715
+ attestation = await deps.getAttestation();
3716
+ } catch (err) {
3717
+ throw new AttestationError(err instanceof Error ? err.message : String(err));
3718
+ }
3719
+ }
3720
+ deps.onPhase("checking");
3721
+ return client.submitCheck(
3722
+ "liveness",
3723
+ { clipKey, attestation, captureChannel: deps.artifacts.captureChannel },
3724
+ { idempotencyKey }
3725
+ );
3726
+ },
3727
+ {
3728
+ onAttestationInvalid: () => {
3729
+ attestation = null;
3730
+ }
3731
+ }
3732
+ );
3733
+ }
3734
+ function buildFaceMatchSubmit(deps, keyframe) {
3735
+ let imageKey = null;
3736
+ return () => runSubmission(deps, async (client, idempotencyKey) => {
3737
+ if (imageKey === null) {
3738
+ deps.onPhase("uploading");
3739
+ const presigned = await client.presign("image", KEYFRAME_MIME, keyframe.size);
3740
+ await client.uploadToSpaces(presigned.uploadUrl, keyframe, KEYFRAME_MIME);
3741
+ imageKey = (await client.completeMedia(presigned.key)).key;
3742
+ }
3743
+ deps.onPhase("checking");
3744
+ return client.submitCheck("face_match", { imageKey }, { idempotencyKey });
3745
+ });
3746
+ }
3725
3747
  function classifyFailure(err) {
3726
3748
  if (err instanceof AttestationError) return { kind: "unavailable", reason: "attestation" };
3727
3749
  if (err instanceof HostedApiError) {
@@ -3956,7 +3978,8 @@ function createVerificationInternal(options, internals) {
3956
3978
  };
3957
3979
  };
3958
3980
  let active = null;
3959
- let flowToken = 0;
3981
+ let chain = Promise.resolve();
3982
+ let chainDepth = 0;
3960
3983
  const settleProcessing = async () => {
3961
3984
  let current = await ensureView();
3962
3985
  for (let i2 = 0; i2 < PROCESSING_POLL_MAX && !destroyed && !isTerminalView(current) && frontierStep(current) === void 0 && current.steps.some((step) => step.state === "processing"); i2 += 1) {
@@ -3966,11 +3989,17 @@ function createVerificationInternal(options, internals) {
3966
3989
  }
3967
3990
  return current;
3968
3991
  };
3969
- const runFlow = async (capture, artifacts, token) => {
3970
- const isCancelled = () => destroyed || token !== flowToken || active !== capture;
3992
+ const runFlow = async (bound, artifacts, capturedAttempt) => {
3993
+ const { capture } = bound;
3994
+ const isCancelled = () => destroyed;
3995
+ const ownsHandle = () => bound.alive && bound.attempt === capturedAttempt;
3996
+ const setPhase = (phase) => {
3997
+ if (ownsHandle()) capture.setFlowState(phase);
3998
+ };
3971
3999
  const finish = (result) => {
3972
4000
  if (isCancelled()) return;
3973
4001
  emitResult(result);
4002
+ if (!ownsHandle()) return;
3974
4003
  if (result.status === "retry" && rearm === "auto") {
3975
4004
  capture.handle.retry();
3976
4005
  return;
@@ -3982,7 +4011,7 @@ function createVerificationInternal(options, internals) {
3982
4011
  finish(unavailable(sessionId, "no_recorder"));
3983
4012
  return;
3984
4013
  }
3985
- capture.setFlowState("uploading");
4014
+ setPhase("uploading");
3986
4015
  try {
3987
4016
  await startRegistry();
3988
4017
  if (isCancelled()) return;
@@ -4004,10 +4033,9 @@ function createVerificationInternal(options, internals) {
4004
4033
  artifacts,
4005
4034
  getAttestation,
4006
4035
  getView: () => view ?? current,
4036
+ refreshView,
4007
4037
  applySubmit,
4008
- onPhase: (phase) => {
4009
- if (!isCancelled()) capture.setFlowState(phase);
4010
- },
4038
+ onPhase: setPhase,
4011
4039
  isCancelled
4012
4040
  });
4013
4041
  if (isCancelled()) return;
@@ -4024,18 +4052,43 @@ function createVerificationInternal(options, internals) {
4024
4052
  finish(unavailable(view?.sessionId ?? "", "network"));
4025
4053
  }
4026
4054
  };
4055
+ const enqueueFlow = (bound, artifacts) => {
4056
+ const capturedAttempt = bound.attempt;
4057
+ if (chainDepth > 0 && bound.alive) {
4058
+ bound.capture.setFlowState("uploading");
4059
+ }
4060
+ chainDepth += 1;
4061
+ chain = chain.then(() => runFlow(bound, artifacts, capturedAttempt)).finally(() => {
4062
+ chainDepth -= 1;
4063
+ }).catch(() => void 0);
4064
+ };
4027
4065
  const liveness = (captureOptions) => {
4028
- active?.handle.destroy();
4066
+ active?.capture.handle.destroy();
4067
+ if (active !== null) active.alive = false;
4029
4068
  const capture = createLivenessCaptureInternal(captureOptions, internals.capture);
4030
- active = capture;
4069
+ const bound = { capture, alive: true, attempt: 0 };
4070
+ active = bound;
4031
4071
  capture.handle.on("state", (state) => {
4032
- if (state === "starting") flowToken += 1;
4072
+ if (state === "starting") bound.attempt += 1;
4033
4073
  });
4034
4074
  capture.handle.on("captured", (artifacts) => {
4035
- const token = ++flowToken;
4036
- void Promise.resolve().then(() => runFlow(capture, artifacts, token));
4075
+ void Promise.resolve().then(() => enqueueFlow(bound, artifacts));
4037
4076
  });
4038
- return capture.handle;
4077
+ const inner = capture.handle;
4078
+ return {
4079
+ get state() {
4080
+ return inner.state;
4081
+ },
4082
+ on: (event, handler) => inner.on(event, handler),
4083
+ start: () => inner.start(),
4084
+ retry: () => inner.retry(),
4085
+ switchCamera: () => inner.switchCamera(),
4086
+ destroy: () => {
4087
+ bound.alive = false;
4088
+ if (active === bound) active = null;
4089
+ inner.destroy();
4090
+ }
4091
+ };
4039
4092
  };
4040
4093
  return {
4041
4094
  consent: () => ensureConsent(),
@@ -4045,8 +4098,11 @@ function createVerificationInternal(options, internals) {
4045
4098
  destroy: () => {
4046
4099
  destroyed = true;
4047
4100
  lifetime.abort();
4048
- active?.handle.destroy();
4049
- active = null;
4101
+ if (active !== null) {
4102
+ active.alive = false;
4103
+ active.capture.handle.destroy();
4104
+ active = null;
4105
+ }
4050
4106
  emitter.clear();
4051
4107
  }
4052
4108
  };