@structured-id/ui-core 4.14.0 → 4.14.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@structured-id/ui-core",
3
- "version": "4.14.0",
3
+ "version": "4.14.1",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -86,7 +86,7 @@
86
86
 
87
87
  <script setup lang="ts">
88
88
  import { reactive, computed, watch } from "vue";
89
- import type { Profile } from "@structured-id/proto/sid/v1/identity/identity";
89
+ import type { Profile } from "../composables/useIdentityApi";
90
90
 
91
91
  const props = withDefaults(
92
92
  defineProps<{
@@ -52,7 +52,7 @@
52
52
  </div>
53
53
 
54
54
  <q-list v-else-if="credentials.length > 0" separator>
55
- <q-item v-for="cred in credentials" :key="cred.id">
55
+ <q-item v-for="cred in credentials" :key="cred.id.toString()">
56
56
  <q-item-section avatar>
57
57
  <q-icon :name="credIcon(cred.type)" :color="credColor(cred.type)" />
58
58
  </q-item-section>
@@ -96,11 +96,9 @@
96
96
  </template>
97
97
 
98
98
  <script setup lang="ts">
99
- import {
100
- type Credential,
101
- CredentialType,
102
- } from "@structured-id/proto/sid/v1/identity/identity";
99
+ import { CredentialType } from "@structured-id/proto/sid/v1/identity/identity";
103
100
  import { Timestamp } from "@structured-id/proto/google/protobuf/timestamp";
101
+ import type { Credential } from "../composables/useIdentityApi";
104
102
  import type { FactorCategory } from "../composables/useSecurityLevel";
105
103
 
106
104
  defineProps<{
@@ -1,5 +1,10 @@
1
1
  import { describe, it, expect } from "vitest";
2
- import { ref } from "vue";
2
+ import { ref, shallowRef } from "vue";
3
+ import { CredentialId, PrincipalId } from "@structured-id/ids";
4
+ import type {
5
+ Credential as IdentityCredential,
6
+ Principal as IdentityPrincipal,
7
+ } from "./useIdentityApi";
3
8
  import {
4
9
  useSecurityLevel,
5
10
  SecurityLevel,
@@ -42,7 +47,6 @@ function makeCred(
42
47
 
43
48
  function makePrincipal(type: PrincipalType, verified: boolean): Principal {
44
49
  return {
45
- id: "p-1",
46
50
  type,
47
51
  value: "test",
48
52
  verified,
@@ -54,6 +58,30 @@ function makePrincipal(type: PrincipalType, verified: boolean): Principal {
54
58
  // ── Security Level ──
55
59
 
56
60
  describe("useSecurityLevel", () => {
61
+ // Regression: the assessment took the wire types, so the typed lists the
62
+ // identity composable answers (held in shallow refs) did not fit it.
63
+ it("assesses the identity composable's typed lists", () => {
64
+ const creds = shallowRef<IdentityCredential[]>([
65
+ {
66
+ ...makeCred(CredentialType.OPAQUE),
67
+ id: CredentialId.parse("0192f3a4-7c1e-7b2a-9d4e-3f5a6b7c8d50"),
68
+ },
69
+ ]);
70
+ const principals = shallowRef<IdentityPrincipal[]>([
71
+ {
72
+ ...makePrincipal(PrincipalType.EMAIL, true),
73
+ id: PrincipalId.parse("0192f3a4-7c1e-7b2a-9d4e-3f5a6b7c8d51"),
74
+ sourceEmailId: undefined,
75
+ },
76
+ ]);
77
+ const { factorCount, recoveryMethods } = useSecurityLevel(
78
+ creds,
79
+ principals,
80
+ );
81
+ expect(factorCount.value).toBe(1);
82
+ expect(recoveryMethods.value).toContain("recovery_email");
83
+ });
84
+
57
85
  it("MINIMAL with no credentials", () => {
58
86
  const { securityLevel } = useSecurityLevel(ref([]), ref([]));
59
87
  expect(securityLevel.value).toBe(SecurityLevel.MINIMAL);
@@ -13,6 +13,15 @@ import {
13
13
  PrincipalType,
14
14
  } from "@structured-id/proto/sid/v1/identity/identity";
15
15
 
16
+ /** What the assessment reads of a credential: its kind and authenticator. */
17
+ export type CredentialFacts = Pick<Credential, "type" | "info">;
18
+
19
+ /** What the assessment reads of a login handle: its kind and proof. */
20
+ export type PrincipalFacts = Pick<
21
+ Principal,
22
+ "type" | "verified" | "needsAddressConfirmation"
23
+ >;
24
+
16
25
  // ── Security Level ──
17
26
 
18
27
  export enum SecurityLevel {
@@ -66,7 +75,7 @@ const RECOVERABILITY_COLORS: Record<RecoverabilityLevel, string> = {
66
75
 
67
76
  export type FactorCategory = "knowledge" | "possession" | "inherence";
68
77
 
69
- function getCategory(cred: Credential): FactorCategory | null {
78
+ function getCategory(cred: CredentialFacts): FactorCategory | null {
70
79
  switch (cred.type) {
71
80
  case CredentialType.OPAQUE:
72
81
  case CredentialType.LEGACY_HASH:
@@ -89,7 +98,7 @@ function getCategory(cred: Credential): FactorCategory | null {
89
98
  }
90
99
  }
91
100
 
92
- function isHardwareKey(cred: Credential): boolean {
101
+ function isHardwareKey(cred: CredentialFacts): boolean {
93
102
  return (
94
103
  cred.type === CredentialType.WEBAUTHN &&
95
104
  cred.info.oneofKind === "webauthnInfo" &&
@@ -113,8 +122,8 @@ export interface ActionNudge {
113
122
  // ── Composable ──
114
123
 
115
124
  export function useSecurityLevel(
116
- credentials: Ref<Credential[]>,
117
- identifiers: Ref<Principal[]>,
125
+ credentials: Readonly<Ref<readonly CredentialFacts[]>>,
126
+ identifiers: Readonly<Ref<readonly PrincipalFacts[]>>,
118
127
  ) {
119
128
  const authFactors = computed(() =>
120
129
  credentials.value.filter((c) => c.type !== CredentialType.RECOVERY),