blob: 015c6d6892da5b686dbbc6d6212c66de09da6cd4 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
/**
* Pure routing logic for the workspaces feature — zero DOM, zero effects, zero Svelte.
*
* The app is URL-driven: the root path `/` is the workspaces HOME (lists all
* workspaces); a single path segment `/<id>` opens the workspace with that id
* (the slug). This module holds the pure mapping from a pathname to a `Route`,
* plus the slug-validation rules mirrored from the backend's `PUT /workspaces/:id`.
*/
/**
* The workspace slug regex (mirrors the backend's `PUT /workspaces/:id`
* validation): 1–40 chars, lowercase alphanumeric with internal hyphens only
* (no leading/trailing hyphen). `"default"` matches and is a valid (but
* non-deletable) id.
*/
export const WORKSPACE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;
/** A route derived from the URL path. */
export type Route = { readonly kind: "home" } | { readonly kind: "workspace"; readonly id: string };
/** The reserved id of the always-present fallback workspace. */
export const DEFAULT_WORKSPACE_ID = "default";
/**
* Parse a pathname into a `Route`. `/` (or empty) → home; a leading segment →
* the workspace with that id (URL-decoded, surrounding slashes trimmed). Deeper
* paths take their FIRST segment (nested routes are not used in v1). Pure:
* pathname in, route out. Does NOT validate the slug — an invalid id still
* produces a `workspace` route; the backend's ensure call rejects it (the FE
* surfaces the error).
*/
export function parsePath(pathname: string): Route {
const trimmed = pathname.replace(/^\/+|\/+$/g, "");
if (trimmed === "") return { kind: "home" };
const first = trimmed.split("/")[0] ?? "";
const id = safeDecode(first);
if (id === "") return { kind: "home" };
return { kind: "workspace", id };
}
/**
* Whether a slug is valid for a NEW workspace (the form the backend accepts).
* Used by the home view's "new workspace" input before navigating.
*/
export function isValidSlug(slug: string): boolean {
return WORKSPACE_SLUG_RE.test(slug);
}
/**
* Build the URL path for a workspace id. Used when navigating to / linking a
* workspace. Pure: id in, path string out.
*/
export function workspacePath(id: string): string {
return `/${id}`;
}
function safeDecode(segment: string): string {
try {
return decodeURIComponent(segment);
} catch {
return segment;
}
}
|