diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 815a4d7b8..d4490e1bc 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -4,3 +4,4 @@ export * as SpeckleViewer from './viewer/index.js' // export * as Environment from './environment/index.js' // Import from @speckle/shared/dist/... export * as Automate from './automate/index.js' export * from './core/index.js' +export * from './workspaces/index.js' diff --git a/packages/shared/src/workspaces/errors/index.ts b/packages/shared/src/workspaces/errors/index.ts new file mode 100644 index 000000000..8aaf21b54 --- /dev/null +++ b/packages/shared/src/workspaces/errors/index.ts @@ -0,0 +1,37 @@ +export const VALID_SLUG_CHARACTERS_REGEX = /^[a-z0-9-]+$/ +export const VALID_SLUG_BOUNDARY_REGEX = /^[a-z0-9].*[a-z0-9]$/ +const MIN_SLUG_LENGTH = 3 +const MAX_SLUG_LENGTH = 30 + +export class InvalidWorkspaceSlugError extends Error { + constructor(message: string) { + super(message) + this.name = 'InvalidWorkspaceSlugError' + } +} + +export function validateWorkspaceSlug(slug: string): void { + if (slug.length < MIN_SLUG_LENGTH) { + throw new InvalidWorkspaceSlugError( + `Workspace slug must be at least ${MIN_SLUG_LENGTH} characters long.` + ) + } + + if (slug.length > MAX_SLUG_LENGTH) { + throw new InvalidWorkspaceSlugError( + `Workspace slug must not exceed ${MAX_SLUG_LENGTH} characters.` + ) + } + + if (!VALID_SLUG_CHARACTERS_REGEX.test(slug)) { + throw new InvalidWorkspaceSlugError( + 'Workspace slug must contain only lowercase letters, numbers, and hyphens.' + ) + } + + if (!VALID_SLUG_BOUNDARY_REGEX.test(slug)) { + throw new InvalidWorkspaceSlugError( + 'Workspace slug cannot start or end with a hyphen.' + ) + } +} diff --git a/packages/shared/src/workspaces/index.ts b/packages/shared/src/workspaces/index.ts new file mode 100644 index 000000000..1522f97a6 --- /dev/null +++ b/packages/shared/src/workspaces/index.ts @@ -0,0 +1 @@ +export * from './errors/index.js'