@streamscloud/kit 0.87.0 → 0.89.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.
@@ -2,5 +2,5 @@ export type { CursorPayload, CursorResult } from './cursor-result';
2
2
  export { ContinuationToken } from './continuation-token';
3
3
  export { Deferred } from './deferred';
4
4
  export { AppEvent, EventDispatcher } from './event-dispatcher';
5
- export { generateHandle } from './handle-generator';
6
5
  export { createGQLClient } from './graphql';
6
+ export { generateHandle, HANDLE_DEFAULT_MAX_LENGTH, HANDLE_PATTERN } from './url-name';
@@ -2,5 +2,5 @@
2
2
  export { ContinuationToken } from './continuation-token';
3
3
  export { Deferred } from './deferred';
4
4
  export { AppEvent, EventDispatcher } from './event-dispatcher';
5
- export { generateHandle } from './handle-generator';
6
5
  export { createGQLClient } from './graphql';
6
+ export { generateHandle, HANDLE_DEFAULT_MAX_LENGTH, HANDLE_PATTERN } from './url-name';
@@ -0,0 +1,4 @@
1
+ export declare const HANDLE_DEFAULT_MAX_LENGTH = 80;
2
+ export declare const HANDLE_PATTERN: RegExp;
3
+ /** Mirrors the backend's `UrlName.From` (AnyAscii, same version on both sides) — the server compares names by this handle, so keep both in lockstep. */
4
+ export declare const generateHandle: (text: string | null | undefined, maxLength?: number) => string;
@@ -0,0 +1,19 @@
1
+ import anyAscii from 'any-ascii';
2
+ export const HANDLE_DEFAULT_MAX_LENGTH = 80;
3
+ export const HANDLE_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
4
+ const STARTS_WITH_SYMBOL = /^\p{S}/u;
5
+ const graphemes = new Intl.Segmenter('und', { granularity: 'grapheme' });
6
+ const dropSymbols = (text) => Array.from(graphemes.segment(text), ({ segment }) => segment)
7
+ .filter((segment) => !STARTS_WITH_SYMBOL.test(segment))
8
+ .join('');
9
+ /** Mirrors the backend's `UrlName.From` (AnyAscii, same version on both sides) — the server compares names by this handle, so keep both in lockstep. */
10
+ export const generateHandle = (text, maxLength = HANDLE_DEFAULT_MAX_LENGTH) => {
11
+ if (!text) {
12
+ return '';
13
+ }
14
+ const handle = anyAscii(dropSymbols(text))
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, '-')
17
+ .replace(/^-+|-+$/g, '');
18
+ return handle.length <= maxLength ? handle : handle.slice(0, maxLength).replace(/-+$/, '');
19
+ };
@@ -1,8 +1,8 @@
1
+ import { HANDLE_PATTERN } from '../../url-name';
1
2
  import { ValidationLocalization } from './validation-localization';
2
3
  import * as yup from 'yup';
3
4
  const DEFAULT_MIN_LENGTH = 3;
4
5
  const DEFAULT_MAX_LENGTH = 30;
5
- const HANDLE_REGEX = /^[a-z_]([a-z0-9_]|[.-](?![.-]))*[a-z0-9_]$/;
6
6
  const resolveHandleLength = (lengthValidation) => ({
7
7
  minLength: lengthValidation?.minLength ?? DEFAULT_MIN_LENGTH,
8
8
  maxLength: lengthValidation?.maxLength ?? DEFAULT_MAX_LENGTH
@@ -10,7 +10,7 @@ const resolveHandleLength = (lengthValidation) => ({
10
10
  /** Value-level rules of `handleValidationSchema` — within length bounds and matching the handle format. */
11
11
  export const isValidHandle = (value, lengthValidation) => {
12
12
  const { minLength, maxLength } = resolveHandleLength(lengthValidation);
13
- return value.length >= minLength && value.length <= maxLength && HANDLE_REGEX.test(value);
13
+ return value.length >= minLength && value.length <= maxLength && HANDLE_PATTERN.test(value);
14
14
  };
15
15
  export const handleValidationSchema = (lengthValidation) => {
16
16
  const msg = new ValidationLocalization();
@@ -20,5 +20,5 @@ export const handleValidationSchema = (lengthValidation) => {
20
20
  .required(msg.required)
21
21
  .min(minLength, msg.minLength(minLength))
22
22
  .max(maxLength, msg.maxLength(maxLength))
23
- .test('handle-format', msg.badFormat, (val) => !!val && HANDLE_REGEX.test(val));
23
+ .test('handle-format', msg.badFormat, (val) => !!val && HANDLE_PATTERN.test(val));
24
24
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.87.0",
3
+ "version": "0.89.0",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",
@@ -488,10 +488,11 @@
488
488
  "@fontsource/jetbrains-mono": "^5.2.8",
489
489
  "@fontsource/source-sans-pro": "^5.2.5",
490
490
  "@urql/core": "^6.0.1",
491
+ "any-ascii": "^0.3.3",
491
492
  "cleave-zen": "^0.0.17",
492
493
  "colord": "^2.9.3",
493
494
  "dequal": "^2.0.3",
494
- "dompurify": "^3.4.5",
495
+ "dompurify": "^3.4.17",
495
496
  "esm-env": "^1.2.2",
496
497
  "file-type": "^22.1.1",
497
498
  "fuse.js": "^7.3.0",
@@ -500,7 +501,7 @@
500
501
  "nanoid": "^5.1.11",
501
502
  "p-limit": "^7.3.0",
502
503
  "rfdc": "^1.4.1",
503
- "svelte": "^5.57.0",
504
+ "svelte": "^5.57.2",
504
505
  "svelte-awesome-color-picker": "^4.1.2",
505
506
  "svelte-dnd-action": "^0.9.69",
506
507
  "wheel-gestures": "^2.2.48",
@@ -518,11 +519,12 @@
518
519
  "@tsconfig/svelte": "^5.0.8",
519
520
  "@types/node": "^26.6.1",
520
521
  "@urql/core": "^6.0.1",
522
+ "any-ascii": "^0.3.3",
521
523
  "autoprefixer": "^10.6.1",
522
524
  "cleave-zen": "^0.0.17",
523
525
  "colord": "^2.9.3",
524
526
  "dequal": "^2.0.3",
525
- "dompurify": "^3.4.5",
527
+ "dompurify": "^3.4.17",
526
528
  "eslint": "^10.10.0",
527
529
  "eslint-config-prettier": "^10.1.8",
528
530
  "eslint-formatter-codeframe": "^7.32.2",
@@ -546,14 +548,14 @@
546
548
  "publint": "^0.3.24",
547
549
  "rfdc": "^1.4.1",
548
550
  "sass": "^1.104.1",
549
- "svelte": "^5.57.0",
551
+ "svelte": "^5.57.2",
550
552
  "svelte-awesome-color-picker": "^4.1.2",
551
553
  "svelte-check": "^4.7.6",
552
554
  "svelte-dnd-action": "^0.9.69",
553
555
  "svelte-preprocess": "^6.0.5",
554
556
  "typescript": "^6.0.3",
555
557
  "typescript-eslint": "^8.70.0",
556
- "vite": "^8.3.0",
558
+ "vite": "^8.3.5",
557
559
  "vite-tsconfig-paths": "^6.1.1",
558
560
  "wheel-gestures": "^2.2.48",
559
561
  "yup": "^1.7.1"
@@ -1 +0,0 @@
1
- export declare const generateHandle: (base: string | null | undefined) => string;
@@ -1,32 +0,0 @@
1
- const SPEC_SYMBOLS = [
2
- { symbol: 'å', replacement: 'a' },
3
- { symbol: 'Å', replacement: 'A' },
4
- { symbol: 'æ', replacement: 'ae' },
5
- { symbol: 'Æ', replacement: 'Ae' },
6
- { symbol: 'ø', replacement: 'o' },
7
- { symbol: 'Ø', replacement: 'O' },
8
- { symbol: 'ö', replacement: 'o' },
9
- { symbol: 'Ö', replacement: 'O' },
10
- { symbol: 'ä', replacement: 'a' },
11
- { symbol: 'Ä', replacement: 'A' }
12
- ];
13
- export const generateHandle = (base) => {
14
- if (!base) {
15
- return '';
16
- }
17
- let handle = base;
18
- // Replace nordic/special chars
19
- for (const { symbol, replacement } of SPEC_SYMBOLS) {
20
- handle = handle.replace(new RegExp(symbol, 'g'), replacement);
21
- }
22
- handle = handle
23
- // Insert hyphen before uppercase (camelCase → kebab-case)
24
- .replace(/([a-z])([A-Z])/g, '$1-$2')
25
- // Lowercase
26
- .toLowerCase()
27
- // Replace any non-alphanumeric with hyphen
28
- .replace(/[^a-z0-9]+/g, '-')
29
- // Remove leading/trailing hyphens
30
- .replace(/^-+|-+$/g, '');
31
- return handle;
32
- };