@descope/flow-components 3.9.1 → 3.10.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.
Files changed (35) hide show
  1. package/dist/fm/222.js +1 -1
  2. package/dist/fm/222.js.map +1 -1
  3. package/dist/fm/467.js +1 -1
  4. package/dist/fm/467.js.map +1 -1
  5. package/dist/fm/741.js +2 -0
  6. package/dist/fm/741.js.map +1 -0
  7. package/dist/fm/985.js +1 -1
  8. package/dist/fm/985.js.map +1 -1
  9. package/dist/fm/@mf-types/compiled-types/MultiLineMappings/MultiLineMappings.d.ts +31 -0
  10. package/dist/fm/@mf-types/compiled-types/MultiLineMappings/index.d.ts +1 -0
  11. package/dist/fm/@mf-types/compiled-types/NewPassword/NewPassword.d.ts +4 -0
  12. package/dist/fm/@mf-types/compiled-types/componentClasses.d.ts +1 -0
  13. package/dist/fm/@mf-types/compiled-types/components.d.ts +1 -0
  14. package/dist/fm/__federation_expose_componentClasses.js +1 -1
  15. package/dist/fm/__federation_expose_componentClasses.js.map +1 -1
  16. package/dist/fm/__federation_expose_components.js +1 -1
  17. package/dist/fm/__federation_expose_theme.js +1 -1
  18. package/dist/fm/__federation_expose_theme.js.map +1 -1
  19. package/dist/fm/flowComponents.js +1 -1
  20. package/dist/fm/flowComponents.js.map +1 -1
  21. package/dist/fm/main.js +1 -1
  22. package/dist/fm/main.js.map +1 -1
  23. package/dist/fm/mf-manifest.json +2 -2
  24. package/dist/fm/mf-stats.json +2 -2
  25. package/dist/index.cjs.js +130 -19
  26. package/dist/index.d.ts +109 -74
  27. package/dist/index.esm.js +56 -13
  28. package/dist/types/MultiLineMappings/MultiLineMappings.d.ts +31 -0
  29. package/dist/types/MultiLineMappings/index.d.ts +1 -0
  30. package/dist/types/NewPassword/NewPassword.d.ts +4 -0
  31. package/dist/types/componentClasses.d.ts +1 -0
  32. package/dist/types/components.d.ts +1 -0
  33. package/package.json +2 -2
  34. package/dist/fm/477.js +0 -2
  35. package/dist/fm/477.js.map +0 -1
@@ -5,7 +5,7 @@
5
5
  "name": "flowComponents",
6
6
  "type": "app",
7
7
  "buildInfo": {
8
- "buildVersion": "3.9.1",
8
+ "buildVersion": "3.10.0",
9
9
  "buildName": "@descope/flow-components"
10
10
  },
11
11
  "remoteEntry": {
@@ -51,7 +51,7 @@
51
51
  "assets": {
52
52
  "js": {
53
53
  "sync": [
54
- "477.js",
54
+ "741.js",
55
55
  "__federation_expose_components.js"
56
56
  ],
57
57
  "async": []
@@ -5,7 +5,7 @@
5
5
  "name": "flowComponents",
6
6
  "type": "app",
7
7
  "buildInfo": {
8
- "buildVersion": "3.9.1",
8
+ "buildVersion": "3.10.0",
9
9
  "buildName": "@descope/flow-components"
10
10
  },
11
11
  "remoteEntry": {
@@ -58,7 +58,7 @@
58
58
  "assets": {
59
59
  "js": {
60
60
  "sync": [
61
- "477.js",
61
+ "741.js",
62
62
  "__federation_expose_components.js"
63
63
  ],
64
64
  "async": []
package/dist/index.cjs.js CHANGED
@@ -97739,6 +97739,8 @@ descope-enriched-text {
97739
97739
  'data-password-policy-value-minlength',
97740
97740
  'data-password-policy-value-passwordstrength',
97741
97741
  'data-password-policy-actual-passwordstrength',
97742
+ 'data-password-policy-value-disallowedchars',
97743
+ 'data-password-policy-value-email',
97742
97744
  ];
97743
97745
  const dataAttrs = ['data', 'active-policies', 'overrides', ...overrideAttrs];
97744
97746
  const policyAttrs = ['label', 'value', ...dataAttrs];
@@ -97857,6 +97859,46 @@ descope-enriched-text {
97857
97859
  };
97858
97860
  }
97859
97861
  }
97862
+
97863
+ // disallowedchars: this stores the configured char list in
97864
+ // overrides.disallowedchars.value so the message can interpolate
97865
+ // `{{value}}`. The regex pattern itself is built upstream (orchestrator
97866
+ // or caller) and shipped on the policy entry — it is not derived from
97867
+ // this override. When the attribute is cleared, drop the override so
97868
+ // the panel doesn't keep stale data.
97869
+ if (attrName === 'data-password-policy-value-disallowedchars') {
97870
+ if (newValue) {
97871
+ this.#overrides = {
97872
+ ...this.#overrides,
97873
+ disallowedchars: {
97874
+ ...this.#overrides?.disallowedchars,
97875
+ value: newValue,
97876
+ },
97877
+ };
97878
+ } else if (this.#overrides?.disallowedchars) {
97879
+ const { disallowedchars: _drop, ...rest } = this.#overrides;
97880
+ this.#overrides = rest;
97881
+ }
97882
+ }
97883
+
97884
+ // disallowemail: stash the user's email so the STR_NEQ_CI comparator
97885
+ // has an `expected` to compare against the live password value. Clear
97886
+ // the override when the attribute is removed/empty so we don't keep
97887
+ // blocking against a previous user's email.
97888
+ if (attrName === 'data-password-policy-value-email') {
97889
+ if (newValue) {
97890
+ this.#overrides = {
97891
+ ...this.#overrides,
97892
+ disallowemail: {
97893
+ ...this.#overrides?.disallowemail,
97894
+ expected: newValue,
97895
+ },
97896
+ };
97897
+ } else if (this.#overrides?.disallowemail) {
97898
+ const { disallowemail: _drop, ...rest } = this.#overrides;
97899
+ this.#overrides = rest;
97900
+ }
97901
+ }
97860
97902
  }
97861
97903
 
97862
97904
  this.renderItems(this.#availablePolicies, this.#activePolicies, this.#overrides);
@@ -97921,6 +97963,7 @@ descope-enriched-text {
97921
97963
  }
97922
97964
 
97923
97965
  const { pattern, message, data, compare } = policy;
97966
+ const normalizedCompare = typeof compare === 'string' ? compare.toUpperCase() : compare;
97924
97967
 
97925
97968
  if ((!pattern && !compare) || !message) {
97926
97969
  return results;
@@ -97934,9 +97977,23 @@ descope-enriched-text {
97934
97977
  if (pattern) {
97935
97978
  const exp = new RegExp(interpolateString(pattern, data));
97936
97979
  validationResult.valid = exp.test(this.value);
97980
+ } else if (normalizedCompare === 'STR_NEQ_CI') {
97981
+ // Compare the live password against the configured string AND its
97982
+ // local-part (before '@'), case-insensitively. Used by the
97983
+ // disallowemail policy.
97984
+ const expected = (data?.expected ?? '').toLowerCase();
97985
+ const actual = (this.value ?? '').toLowerCase();
97986
+ if (!expected || !actual) {
97987
+ // nothing to compare → mark valid so we don't block the flow
97988
+ validationResult.valid = true;
97989
+ } else {
97990
+ const at = expected.indexOf('@');
97991
+ const localPart = at > 0 ? expected.slice(0, at) : expected;
97992
+ validationResult.valid = actual !== expected && actual !== localPart;
97993
+ }
97937
97994
  } else if (compare) {
97938
97995
  validationResult.valid = this.compareValues(
97939
- compare,
97996
+ normalizedCompare,
97940
97997
  data?.expected ?? -1,
97941
97998
  data?.actual ?? -1
97942
97999
  );
@@ -97952,13 +98009,18 @@ descope-enriched-text {
97952
98009
  return !this.validate().some(({ valid }) => valid === false);
97953
98010
  }
97954
98011
 
97955
- getValidationItemTemplate({ valid, message }) {
98012
+ buildValidationItem({ valid, message }) {
97956
98013
  const status = !this.value ? 'none' : valid;
97957
- return `
97958
- <li class="item" data-valid="${status}">
97959
- <span class="message">${message}</span>
97960
- </li>
97961
- `;
98014
+ const li = document.createElement('li');
98015
+ li.className = 'item';
98016
+ li.dataset.valid = status;
98017
+ const span = document.createElement('span');
98018
+ span.className = 'message';
98019
+ // `textContent` handles any tenant-configured string in `message` safely
98020
+ // (e.g. the disallowedchars list) without needing to escape HTML.
98021
+ span.textContent = message ?? '';
98022
+ li.appendChild(span);
98023
+ return li;
97962
98024
  }
97963
98025
 
97964
98026
  renderItems(availablePolicies, activePolicies) {
@@ -97966,7 +98028,9 @@ descope-enriched-text {
97966
98028
  return;
97967
98029
  }
97968
98030
 
97969
- this.list.innerHTML = this.validate().map(this.getValidationItemTemplate.bind(this)).join('');
98031
+ this.list.replaceChildren(
98032
+ ...this.validate().map(this.buildValidationItem.bind(this)),
98033
+ );
97970
98034
  }
97971
98035
 
97972
98036
  updateLabel(val) {
@@ -98067,6 +98131,8 @@ descope-enriched-text {
98067
98131
  'available-policies',
98068
98132
  'data-password-policy-value-minlength',
98069
98133
  'data-password-policy-value-passwordstrength',
98134
+ 'data-password-policy-value-disallowedchars',
98135
+ 'data-password-policy-value-email',
98070
98136
  'label-type',
98071
98137
  'manual-visibility-toggle',
98072
98138
  ],
@@ -106869,6 +106935,7 @@ const NotificationClass = index_cjsExports.NotificationClass;
106869
106935
  const GridClass = index_cjsExports.GridClass;
106870
106936
  const BadgeClass = index_cjsExports.BadgeClass;
106871
106937
  const MultiSelectComboBoxClass = index_cjsExports.MultiSelectComboBoxClass;
106938
+ const MultiLineMappingsClass = index_cjsExports.MultiLineMappingsClass;
106872
106939
  const AvatarClass = index_cjsExports.AvatarClass;
106873
106940
  const UserAttributeClass = index_cjsExports.UserAttributeClass;
106874
106941
  const UserAuthMethodClass = index_cjsExports.UserAuthMethodClass;
@@ -107116,6 +107183,11 @@ const Loader = React__default.default.forwardRef(({ variant, color, ...restProps
107116
107183
 
107117
107184
  const Logo = React__default.default.forwardRef(({ width, height, ...props }, ref) => (React__default.default.createElement("descope-logo", { "st-width": width, "st-height": height, ref: ref, ...props })));
107118
107185
 
107186
+ // Escape characters that have a special meaning inside a JS regex character
107187
+ // class so they appear as literals (used to build the disallowedchars regex
107188
+ // from a tenant-configured chars list).
107189
+ const escapeRegexClassChars = (s) => s.replace(/[\\\]\-^]/g, '\\$&');
107190
+ const buildDisallowedCharsPattern = (chars) => chars ? `^[^${escapeRegexClassChars(chars)}]*$` : '';
107119
107191
  const defaultProps = {
107120
107192
  'has-validation': false,
107121
107193
  'policy-label': 'Passwords must have:',
@@ -107133,6 +107205,7 @@ const defaultProps = {
107133
107205
  'data-password-policy-pattern-nonalphanumeric': '[^a-zA-Z0-9]',
107134
107206
  // non-user-editable comparisons
107135
107207
  'data-password-policy-compare-passwordstrength': 'GTE',
107208
+ 'data-password-policy-compare-disallowemail': 'STR_NEQ_CI',
107136
107209
  // props to override with data from policy
107137
107210
  'data-password-policy-value-minlength': '8',
107138
107211
  // translatable props
@@ -107143,30 +107216,50 @@ const defaultProps = {
107143
107216
  'data-password-policy-message-number': '1 number',
107144
107217
  'data-password-policy-message-nonalphanumeric': '1 symbol',
107145
107218
  'data-password-policy-message-passwordstrength': 'Password strength',
107219
+ 'data-password-policy-message-disallowedchars': 'Does not contain: {{value}}',
107220
+ 'data-password-policy-message-disallowemail': 'Does not match your email',
107146
107221
  'st-policy-preview-background-color': 'transparent',
107147
107222
  'st-policy-preview-padding': '0'
107148
107223
  };
107149
107224
  const NewPassword = React__default.default.forwardRef((props, ref) => {
107150
107225
  const mergedProps = { ...defaultProps, ...props };
107226
+ // Dynamic key lookups (`data-password-policy-${kind}-${id}`) below sit
107227
+ // outside the typed Props surface, so we read them through a narrow
107228
+ // Record alias rather than widening the whole mergedProps to `any`.
107229
+ const mergedPropsByKey = mergedProps;
107151
107230
  /* this logic is cloned in the orchestration service (context.go file)
107152
- * make sure to update both places when changing it
107153
- */
107154
- const availablePolicies = [
107231
+ * make sure to update both places when changing it
107232
+ */
107233
+ const availablePolicies = JSON.stringify([
107155
107234
  'minlength',
107156
107235
  'lowercase',
107157
107236
  'uppercase',
107158
107237
  'anyletter',
107159
107238
  'number',
107160
107239
  'nonalphanumeric',
107161
- 'passwordstrength'
107162
- ].map((id) => ({
107163
- id,
107164
- message: mergedProps[`data-password-policy-message-${id}`],
107165
- pattern: mergedProps[`data-password-policy-pattern-${id}`],
107166
- compare: mergedProps[`data-password-policy-compare-${id}`],
107167
- data: mergedProps[`data-password-policy-data-${id}`]
107240
+ 'passwordstrength',
107241
+ 'disallowedchars',
107242
+ 'disallowemail'
107243
+ ].map((id) => {
107244
+ const entry = {
107245
+ id,
107246
+ message: mergedPropsByKey[`data-password-policy-message-${id}`],
107247
+ pattern: mergedPropsByKey[`data-password-policy-pattern-${id}`],
107248
+ compare: mergedPropsByKey[`data-password-policy-compare-${id}`],
107249
+ data: mergedPropsByKey[`data-password-policy-data-${id}`]
107250
+ };
107251
+ // disallowedchars: the pattern is `^[^<escaped chars>]*$`, built from
107252
+ // the configured chars list. Done here (rather than as a static
107253
+ // pattern with a `{{value}}` placeholder) so chars like `]`, `^`, `-`,
107254
+ // `\` are escaped instead of breaking the character class.
107255
+ if (id === 'disallowedchars') {
107256
+ const chars = mergedPropsByKey['data-password-policy-value-disallowedchars'] || '';
107257
+ entry.pattern = buildDisallowedCharsPattern(chars);
107258
+ entry.data = { value: chars };
107259
+ }
107260
+ return entry;
107168
107261
  }));
107169
- return (React__default.default.createElement("descope-new-password", { ...mergedProps, ref: ref, "available-policies": JSON.stringify(availablePolicies || []) }));
107262
+ return (React__default.default.createElement("descope-new-password", { ...mergedProps, ref: ref, "available-policies": availablePolicies }));
107170
107263
  });
107171
107264
 
107172
107265
  const PhoneCountrySelection = React__default.default.forwardRef((props, ref) => React__default.default.createElement("descope-phone-field", { ...props, ref: ref }));
@@ -107359,6 +107452,22 @@ const SAMLGroupMappings = React__default.default.forwardRef(({ options, size = '
107359
107452
  return (React__default.default.createElement("descope-saml-group-mappings", { size: size, ...props, options: serializedOptions ?? undefined, ref: ref }));
107360
107453
  });
107361
107454
 
107455
+ const MultiLineMappings = React__default.default.forwardRef(({ data, ...props }, ref) => {
107456
+ const serializedData = React.useMemo(() => {
107457
+ if (!data)
107458
+ return undefined;
107459
+ try {
107460
+ return JSON.stringify(data);
107461
+ }
107462
+ catch (e) {
107463
+ // eslint-disable-next-line no-console
107464
+ console.error('could not parse data string from attribute "data" -', e.message);
107465
+ return undefined;
107466
+ }
107467
+ }, [data]);
107468
+ return (React__default.default.createElement("descope-multi-line-mappings", { data: serializedData, ...props, ref: ref }));
107469
+ });
107470
+
107362
107471
  const UserAuthMethod = React__default.default.forwardRef(({ methodIcon, methodIconDark, buttonIcon, buttonIconDark, fulfilledButtonIcon, fulfilledButtonIconDark, ...props }, ref) => (React__default.default.createElement("descope-user-auth-method", { ...props, ref: ref },
107363
107472
  methodIcon && methodIconDark && React__default.default.createElement(Icon, { icon: methodIcon, "src-dark": methodIconDark, slot: "method-icon", noColor: true }),
107364
107473
  buttonIcon && buttonIconDark && React__default.default.createElement(Icon, { icon: buttonIcon, "src-dark": buttonIconDark, slot: "button-icon", noColor: true, width: "1em", height: "1em" }),
@@ -107543,6 +107652,8 @@ exports.MappingsField = MappingsField;
107543
107652
  exports.MappingsFieldClass = MappingsFieldClass;
107544
107653
  exports.Modal = Modal;
107545
107654
  exports.ModalClass = ModalClass;
107655
+ exports.MultiLineMappings = MultiLineMappings;
107656
+ exports.MultiLineMappingsClass = MultiLineMappingsClass;
107546
107657
  exports.MultiSelect = MultiSelect;
107547
107658
  exports.MultiSelectComboBoxClass = MultiSelectComboBoxClass;
107548
107659
  exports.NOTPImage = NOTPImage;