@stapel/workspaces-react 0.1.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 (111) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/MODULE.md +54 -0
  4. package/README.md +73 -0
  5. package/dist/api/extensions.d.ts +8 -0
  6. package/dist/api/extensions.d.ts.map +1 -0
  7. package/dist/api/extensions.js +8 -0
  8. package/dist/api/extensions.js.map +1 -0
  9. package/dist/api/types.d.ts +51 -0
  10. package/dist/api/types.d.ts.map +1 -0
  11. package/dist/api/types.js +2 -0
  12. package/dist/api/types.js.map +1 -0
  13. package/dist/api/workspacesApi.d.ts +43 -0
  14. package/dist/api/workspacesApi.d.ts.map +1 -0
  15. package/dist/api/workspacesApi.js +31 -0
  16. package/dist/api/workspacesApi.js.map +1 -0
  17. package/dist/flows/errors.d.ts +12 -0
  18. package/dist/flows/errors.d.ts.map +1 -0
  19. package/dist/flows/errors.js +13 -0
  20. package/dist/flows/errors.js.map +1 -0
  21. package/dist/flows/generated/flows.gen.d.ts +19 -0
  22. package/dist/flows/generated/flows.gen.d.ts.map +1 -0
  23. package/dist/flows/generated/flows.gen.js +23 -0
  24. package/dist/flows/generated/flows.gen.js.map +1 -0
  25. package/dist/headless/AcceptInvitation.d.ts +39 -0
  26. package/dist/headless/AcceptInvitation.d.ts.map +1 -0
  27. package/dist/headless/AcceptInvitation.js +27 -0
  28. package/dist/headless/AcceptInvitation.js.map +1 -0
  29. package/dist/headless/Members.d.ts +47 -0
  30. package/dist/headless/Members.d.ts.map +1 -0
  31. package/dist/headless/Members.js +50 -0
  32. package/dist/headless/Members.js.map +1 -0
  33. package/dist/headless/WorkspaceList.d.ts +38 -0
  34. package/dist/headless/WorkspaceList.d.ts.map +1 -0
  35. package/dist/headless/WorkspaceList.js +33 -0
  36. package/dist/headless/WorkspaceList.js.map +1 -0
  37. package/dist/headless/WorkspacesProvider.d.ts +18 -0
  38. package/dist/headless/WorkspacesProvider.d.ts.map +1 -0
  39. package/dist/headless/WorkspacesProvider.js +17 -0
  40. package/dist/headless/WorkspacesProvider.js.map +1 -0
  41. package/dist/i18n/errorsMap.d.ts +10 -0
  42. package/dist/i18n/errorsMap.d.ts.map +1 -0
  43. package/dist/i18n/errorsMap.js +20 -0
  44. package/dist/i18n/errorsMap.js.map +1 -0
  45. package/dist/i18n/generated/errors.gen.d.ts +347 -0
  46. package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
  47. package/dist/i18n/generated/errors.gen.js +177 -0
  48. package/dist/i18n/generated/errors.gen.js.map +1 -0
  49. package/dist/i18n/generated/errors.ru.gen.d.ts +9 -0
  50. package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
  51. package/dist/i18n/generated/errors.ru.gen.js +61 -0
  52. package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
  53. package/dist/i18n/keys.d.ts +55 -0
  54. package/dist/i18n/keys.d.ts.map +1 -0
  55. package/dist/i18n/keys.js +76 -0
  56. package/dist/i18n/keys.js.map +1 -0
  57. package/dist/i18n/ru.d.ts +28 -0
  58. package/dist/i18n/ru.d.ts.map +1 -0
  59. package/dist/i18n/ru.js +49 -0
  60. package/dist/i18n/ru.js.map +1 -0
  61. package/dist/index.d.ts +38 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +36 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/model/context.d.ts +14 -0
  66. package/dist/model/context.d.ts.map +1 -0
  67. package/dist/model/context.js +21 -0
  68. package/dist/model/context.js.map +1 -0
  69. package/dist/model/mutations.d.ts +55 -0
  70. package/dist/model/mutations.d.ts.map +1 -0
  71. package/dist/model/mutations.js +138 -0
  72. package/dist/model/mutations.js.map +1 -0
  73. package/dist/model/queries.d.ts +21 -0
  74. package/dist/model/queries.d.ts.map +1 -0
  75. package/dist/model/queries.js +41 -0
  76. package/dist/model/queries.js.map +1 -0
  77. package/dist/model/queryKeys.d.ts +7 -0
  78. package/dist/model/queryKeys.d.ts.map +1 -0
  79. package/dist/model/queryKeys.js +15 -0
  80. package/dist/model/queryKeys.js.map +1 -0
  81. package/dist/model/runtime.d.ts +26 -0
  82. package/dist/model/runtime.d.ts.map +1 -0
  83. package/dist/model/runtime.js +18 -0
  84. package/dist/model/runtime.js.map +1 -0
  85. package/llms.txt +95 -0
  86. package/manifest.json +705 -0
  87. package/package.json +85 -0
  88. package/src/analytics/generated/events.json +7 -0
  89. package/src/api/extensions.ts +7 -0
  90. package/src/api/types.ts +58 -0
  91. package/src/api/workspacesApi.ts +139 -0
  92. package/src/flows/errors.ts +16 -0
  93. package/src/flows/generated/flows.gen.ts +38 -0
  94. package/src/flows/generated/flows.json +1 -0
  95. package/src/headless/AcceptInvitation.tsx +53 -0
  96. package/src/headless/Members.tsx +89 -0
  97. package/src/headless/WorkspaceList.tsx +58 -0
  98. package/src/headless/WorkspacesProvider.tsx +25 -0
  99. package/src/i18n/errorsMap.ts +31 -0
  100. package/src/i18n/generated/errors.gen.ts +208 -0
  101. package/src/i18n/generated/errors.json +394 -0
  102. package/src/i18n/generated/errors.ru.gen.ts +67 -0
  103. package/src/i18n/keys.ts +83 -0
  104. package/src/i18n/ru.ts +53 -0
  105. package/src/index.ts +113 -0
  106. package/src/model/context.tsx +29 -0
  107. package/src/model/mutations.ts +196 -0
  108. package/src/model/queries.ts +51 -0
  109. package/src/model/queryKeys.ts +20 -0
  110. package/src/model/runtime.ts +46 -0
  111. package/tsconfig.json +26 -0
@@ -0,0 +1,50 @@
1
+ import { useMembers } from "../model/queries.js";
2
+ import { useInviteMembers, useRemoveMember, useUpdateMemberRole, } from "../model/mutations.js";
3
+ /**
4
+ * Headless member roster — a renderless view + invite / role-change / removal
5
+ * controls over one workspace's members. Wires {@link useMembers},
6
+ * {@link useInviteMembers}, {@link useUpdateMemberRole}, and
7
+ * {@link useRemoveMember} and hands a {@link MembersBag} to `children`; bring your
8
+ * own roster / invite form / role menu. Zero visual opinion (frontend-standard §2).
9
+ *
10
+ * ```tsx
11
+ * <Members workspaceId={id}>
12
+ * {({ members, invite, updateRole, remove }) => ( ... )}
13
+ * </Members>
14
+ * ```
15
+ */
16
+ export function Members(props) {
17
+ const query = useMembers(props.workspaceId);
18
+ const inviteMutation = useInviteMembers(props.workspaceId);
19
+ const roleMutation = useUpdateMemberRole(props.workspaceId);
20
+ const removeMutation = useRemoveMember(props.workspaceId);
21
+ return props.children({
22
+ members: query.data?.members ?? [],
23
+ isLoading: query.isLoading,
24
+ isError: query.isError ||
25
+ inviteMutation.isError ||
26
+ roleMutation.isError ||
27
+ removeMutation.isError,
28
+ error: query.error ??
29
+ inviteMutation.error ??
30
+ roleMutation.error ??
31
+ removeMutation.error ??
32
+ null,
33
+ invite: (body) => {
34
+ inviteMutation.mutate(body);
35
+ },
36
+ isInviting: inviteMutation.isPending,
37
+ updateRole: (change) => {
38
+ roleMutation.mutate(change);
39
+ },
40
+ isUpdatingRole: roleMutation.isPending,
41
+ remove: (userId) => {
42
+ removeMutation.mutate(userId);
43
+ },
44
+ isRemoving: removeMutation.isPending,
45
+ refetch: () => {
46
+ void query.refetch();
47
+ },
48
+ });
49
+ }
50
+ //# sourceMappingURL=Members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Members.js","sourceRoot":"","sources":["../../src/headless/Members.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AA6B/B;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CAAC,KAGvB;IACC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5C,MAAM,cAAc,GAAG,gBAAgB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC3D,MAAM,YAAY,GAAG,mBAAmB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,cAAc,GAAG,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC1D,OAAO,KAAK,CAAC,QAAQ,CAAC;QACpB,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE;QAClC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EACL,KAAK,CAAC,OAAO;YACb,cAAc,CAAC,OAAO;YACtB,YAAY,CAAC,OAAO;YACpB,cAAc,CAAC,OAAO;QACxB,KAAK,EACH,KAAK,CAAC,KAAK;YACX,cAAc,CAAC,KAAK;YACpB,YAAY,CAAC,KAAK;YAClB,cAAc,CAAC,KAAK;YACpB,IAAI;QACN,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACf,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QACD,UAAU,EAAE,cAAc,CAAC,SAAS;QACpC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE;YACrB,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;QACD,cAAc,EAAE,YAAY,CAAC,SAAS;QACtC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;YACjB,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;QACD,UAAU,EAAE,cAAc,CAAC,SAAS;QACpC,OAAO,EAAE,GAAG,EAAE;YACZ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { ReactNode } from "react";
2
+ import type { StapelApiError } from "@stapel/core";
3
+ import type { Workspace, WorkspaceCreate } from "../api/types.js";
4
+ /** Render-prop bag for {@link WorkspaceList}. */
5
+ export interface WorkspaceListBag {
6
+ /** The caller's workspaces once loaded (empty before load). */
7
+ readonly workspaces: readonly Workspace[];
8
+ /** The initial list load is in flight (no data yet). */
9
+ readonly isLoading: boolean;
10
+ /** Either the read or the create failed. */
11
+ readonly isError: boolean;
12
+ /** The error, when `isError` (a localizable `StapelApiError`), else null. */
13
+ readonly error: StapelApiError | null;
14
+ /** Create a workspace (owner-seeded). */
15
+ create(body: WorkspaceCreate): void;
16
+ /** A create call is in flight. */
17
+ readonly isCreating: boolean;
18
+ /** The workspace created by the last `create`, else null. */
19
+ readonly created: Workspace | null;
20
+ /** Refetch the list from the server. */
21
+ refetch(): void;
22
+ }
23
+ /**
24
+ * Headless workspace list — a renderless view + create control over the caller's
25
+ * workspaces. Wires {@link useWorkspaces} + {@link useCreateWorkspace} and hands a
26
+ * {@link WorkspaceListBag} to `children`; bring your own list / create form.
27
+ * Zero visual opinion (frontend-standard §2).
28
+ *
29
+ * ```tsx
30
+ * <WorkspaceList>
31
+ * {({ workspaces, create }) => ( ... )}
32
+ * </WorkspaceList>
33
+ * ```
34
+ */
35
+ export declare function WorkspaceList(props: {
36
+ children: (bag: WorkspaceListBag) => ReactNode;
37
+ }): ReactNode;
38
+ //# sourceMappingURL=WorkspaceList.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspaceList.d.ts","sourceRoot":"","sources":["../../src/headless/WorkspaceList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIlE,iDAAiD;AACjD,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,yCAAyC;IACzC,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC,kCAAkC;IAClC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI,CAAC;IACnC,wCAAwC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,QAAQ,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,SAAS,CAAC;CAChD,GAAG,SAAS,CAiBZ"}
@@ -0,0 +1,33 @@
1
+ import { useWorkspaces } from "../model/queries.js";
2
+ import { useCreateWorkspace } from "../model/mutations.js";
3
+ /**
4
+ * Headless workspace list — a renderless view + create control over the caller's
5
+ * workspaces. Wires {@link useWorkspaces} + {@link useCreateWorkspace} and hands a
6
+ * {@link WorkspaceListBag} to `children`; bring your own list / create form.
7
+ * Zero visual opinion (frontend-standard §2).
8
+ *
9
+ * ```tsx
10
+ * <WorkspaceList>
11
+ * {({ workspaces, create }) => ( ... )}
12
+ * </WorkspaceList>
13
+ * ```
14
+ */
15
+ export function WorkspaceList(props) {
16
+ const query = useWorkspaces();
17
+ const mutation = useCreateWorkspace();
18
+ return props.children({
19
+ workspaces: query.data?.workspaces ?? [],
20
+ isLoading: query.isLoading,
21
+ isError: query.isError || mutation.isError,
22
+ error: query.error ?? mutation.error ?? null,
23
+ create: (body) => {
24
+ mutation.mutate(body);
25
+ },
26
+ isCreating: mutation.isPending,
27
+ created: mutation.data ?? null,
28
+ refetch: () => {
29
+ void query.refetch();
30
+ },
31
+ });
32
+ }
33
+ //# sourceMappingURL=WorkspaceList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspaceList.js","sourceRoot":"","sources":["../../src/headless/WorkspaceList.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAsB3D;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,KAE7B;IACC,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAC;IACtC,OAAO,KAAK,CAAC,QAAQ,CAAC;QACpB,UAAU,EAAE,KAAK,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE;QACxC,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;QAC1C,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,IAAI,IAAI;QAC5C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACf,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QACD,UAAU,EAAE,QAAQ,CAAC,SAAS;QAC9B,OAAO,EAAE,QAAQ,CAAC,IAAI,IAAI,IAAI;QAC9B,OAAO,EAAE,GAAG,EAAE;YACZ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;QACvB,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import type { WorkspacesRuntime } from "../model/runtime.js";
3
+ /**
4
+ * Provides the wired {@link WorkspacesRuntime} to every workspaces hook and
5
+ * headless component below it. Bring your own visual shell — this component
6
+ * renders nothing of its own.
7
+ *
8
+ * ```tsx
9
+ * const runtime = createWorkspacesRuntime({ baseUrl: "/workspaces/api/" });
10
+ * // give runtime.client to core's <StapelConfigProvider config={{ client }}>
11
+ * <WorkspacesProvider runtime={runtime}>{app}</WorkspacesProvider>
12
+ * ```
13
+ */
14
+ export declare function WorkspacesProvider(props: {
15
+ runtime: WorkspacesRuntime;
16
+ children: ReactNode;
17
+ }): ReactElement;
18
+ //# sourceMappingURL=WorkspacesProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspacesProvider.d.ts","sourceRoot":"","sources":["../../src/headless/WorkspacesProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB,GAAG,YAAY,CAMf"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { WorkspacesRuntimeContext } from "../model/context.js";
3
+ /**
4
+ * Provides the wired {@link WorkspacesRuntime} to every workspaces hook and
5
+ * headless component below it. Bring your own visual shell — this component
6
+ * renders nothing of its own.
7
+ *
8
+ * ```tsx
9
+ * const runtime = createWorkspacesRuntime({ baseUrl: "/workspaces/api/" });
10
+ * // give runtime.client to core's <StapelConfigProvider config={{ client }}>
11
+ * <WorkspacesProvider runtime={runtime}>{app}</WorkspacesProvider>
12
+ * ```
13
+ */
14
+ export function WorkspacesProvider(props) {
15
+ return (_jsx(WorkspacesRuntimeContext.Provider, { value: props.runtime, children: props.children }));
16
+ }
17
+ //# sourceMappingURL=WorkspacesProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkspacesProvider.js","sourceRoot":"","sources":["../../src/headless/WorkspacesProvider.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAG/D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAGlC;IACC,OAAO,CACL,KAAC,wBAAwB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,CAAC,OAAO,YACpD,KAAK,CAAC,QAAQ,GACmB,CACrC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Remediation } from "./generated/errors.gen.js";
2
+ export { WORKSPACES_ERRORS, WORKSPACES_ERROR_CODES, workspacesErrorBundleEn, } from "./generated/errors.gen.js";
3
+ export type { WorkspacesErrorCode, WorkspacesErrorSpec, Remediation, } from "./generated/errors.gen.js";
4
+ /**
5
+ * Resolve a backend error code to its remediation hint, or `undefined` for a
6
+ * code this module doesn't know (e.g. a cross-cutting `stapel.http.*` fallback).
7
+ * Zero guessing at runtime — a static lookup over the generated map.
8
+ */
9
+ export declare function explainWorkspacesError(code: string): Remediation | undefined;
10
+ //# sourceMappingURL=errorsMap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorsMap.d.ts","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,GACZ,MAAM,2BAA2B,CAAC;AAEnC;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAG5E"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The pair's error map (frontend-standard §4 checklist #7, frontend-core §2.5):
3
+ * the generated `code → { status, params, remediation, en }` catalog plus a
4
+ * tiny `explain()` lookup. Backs the manifest `errors` block and gives hosts a
5
+ * mechanical UX branch beside `t(code, params)`. The map itself is generated
6
+ * from the backend registry (`pnpm gen:errors`); this file only adds the lookup
7
+ * helper and re-exports the public surface.
8
+ */
9
+ import { WORKSPACES_ERRORS } from "./generated/errors.gen.js";
10
+ export { WORKSPACES_ERRORS, WORKSPACES_ERROR_CODES, workspacesErrorBundleEn, } from "./generated/errors.gen.js";
11
+ /**
12
+ * Resolve a backend error code to its remediation hint, or `undefined` for a
13
+ * code this module doesn't know (e.g. a cross-cutting `stapel.http.*` fallback).
14
+ * Zero guessing at runtime — a static lookup over the generated map.
15
+ */
16
+ export function explainWorkspacesError(code) {
17
+ return WORKSPACES_ERRORS[code]
18
+ ?.remediation;
19
+ }
20
+ //# sourceMappingURL=errorsMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorsMap.js","sourceRoot":"","sources":["../../src/i18n/errorsMap.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAG9D,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,2BAA2B,CAAC;AAOnC;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAQ,iBAAkE,CAAC,IAAI,CAAC;QAC9E,EAAE,WAAW,CAAC;AAClB,CAAC"}
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Remediation vocabulary (frontend-core-architecture §2.5). Declared by the
3
+ * backend on the error registry and consumed verbatim from its `errors.json`
4
+ * artifact. A host maps it to UX — retryable → "try again"; `wait_and_retry` →
5
+ * timer from `params.retry_after_minutes`; `verify` → the step-up seam;
6
+ * `fix_input` → highlight the offending field.
7
+ */
8
+ export type Remediation = "retry" | "wait_and_retry" | "reauthenticate" | "verify" | "fix_input" | "contact_support" | "bug";
9
+ export interface WorkspacesErrorSpec {
10
+ /** HTTP status the backend raises this key with. */
11
+ readonly status: number;
12
+ /** `{param}` interpolation slots present in the message. */
13
+ readonly params: readonly string[];
14
+ /** Remediation hint declared by the backend (see {@link Remediation}). */
15
+ readonly remediation: Remediation;
16
+ /** English fallback (source: stapel-auth errors.json). */
17
+ readonly en: string;
18
+ }
19
+ /**
20
+ * The WORKSPACES_ERRORS map — every `error.*` key stapel-auth can raise, keyed by its
21
+ * canonical code. The single source of truth behind the en fallback bundle, the
22
+ * remediation lookup, and the manifest `errors` block.
23
+ */
24
+ export declare const WORKSPACES_ERRORS: {
25
+ readonly "error.400.already_workspace_member": {
26
+ readonly status: 400;
27
+ readonly params: readonly [];
28
+ readonly remediation: "fix_input";
29
+ readonly en: "User is already a member of this workspace";
30
+ };
31
+ readonly "error.400.bad_request": {
32
+ readonly status: 400;
33
+ readonly params: readonly [];
34
+ readonly remediation: "fix_input";
35
+ readonly en: "Bad request";
36
+ };
37
+ readonly "error.400.captcha_invalid": {
38
+ readonly status: 400;
39
+ readonly params: readonly [];
40
+ readonly remediation: "retry";
41
+ readonly en: "Captcha verification failed. Please try again.";
42
+ };
43
+ readonly "error.400.captcha_required": {
44
+ readonly status: 400;
45
+ readonly params: readonly [];
46
+ readonly remediation: "retry";
47
+ readonly en: "Captcha token is required.";
48
+ };
49
+ readonly "error.400.expected_list": {
50
+ readonly status: 400;
51
+ readonly params: readonly [];
52
+ readonly remediation: "fix_input";
53
+ readonly en: "Expected a list of items";
54
+ };
55
+ readonly "error.400.field.blank": {
56
+ readonly status: 400;
57
+ readonly params: readonly ["field"];
58
+ readonly remediation: "fix_input";
59
+ readonly en: "{field} may not be blank";
60
+ };
61
+ readonly "error.400.field.does_not_exist": {
62
+ readonly status: 400;
63
+ readonly params: readonly ["field"];
64
+ readonly remediation: "fix_input";
65
+ readonly en: "{field} does not exist";
66
+ };
67
+ readonly "error.400.field.invalid": {
68
+ readonly status: 400;
69
+ readonly params: readonly ["field"];
70
+ readonly remediation: "fix_input";
71
+ readonly en: "{field} is invalid";
72
+ };
73
+ readonly "error.400.field.invalid_choice": {
74
+ readonly status: 400;
75
+ readonly params: readonly ["field"];
76
+ readonly remediation: "fix_input";
77
+ readonly en: "{field} is not a valid choice";
78
+ };
79
+ readonly "error.400.field.max_length": {
80
+ readonly status: 400;
81
+ readonly params: readonly ["field", "max_length"];
82
+ readonly remediation: "fix_input";
83
+ readonly en: "{field} must be at most {max_length} characters";
84
+ };
85
+ readonly "error.400.field.max_value": {
86
+ readonly status: 400;
87
+ readonly params: readonly ["field", "max_value"];
88
+ readonly remediation: "fix_input";
89
+ readonly en: "{field} must be at most {max_value}";
90
+ };
91
+ readonly "error.400.field.min_length": {
92
+ readonly status: 400;
93
+ readonly params: readonly ["field", "min_length"];
94
+ readonly remediation: "fix_input";
95
+ readonly en: "{field} must be at least {min_length} characters";
96
+ };
97
+ readonly "error.400.field.min_value": {
98
+ readonly status: 400;
99
+ readonly params: readonly ["field", "min_value"];
100
+ readonly remediation: "fix_input";
101
+ readonly en: "{field} must be at least {min_value}";
102
+ };
103
+ readonly "error.400.field.null": {
104
+ readonly status: 400;
105
+ readonly params: readonly ["field"];
106
+ readonly remediation: "fix_input";
107
+ readonly en: "{field} may not be null";
108
+ };
109
+ readonly "error.400.field.required": {
110
+ readonly status: 400;
111
+ readonly params: readonly ["field"];
112
+ readonly remediation: "fix_input";
113
+ readonly en: "{field} is required";
114
+ };
115
+ readonly "error.400.field.unique": {
116
+ readonly status: 400;
117
+ readonly params: readonly ["field"];
118
+ readonly remediation: "fix_input";
119
+ readonly en: "{field} must be unique";
120
+ };
121
+ readonly "error.400.invalid_ad_id": {
122
+ readonly status: 400;
123
+ readonly params: readonly [];
124
+ readonly remediation: "fix_input";
125
+ readonly en: "Invalid advertisement ID";
126
+ };
127
+ readonly "error.400.invalid_role": {
128
+ readonly status: 400;
129
+ readonly params: readonly [];
130
+ readonly remediation: "fix_input";
131
+ readonly en: "Invalid role";
132
+ };
133
+ readonly "error.400.invitation_already_used": {
134
+ readonly status: 400;
135
+ readonly params: readonly [];
136
+ readonly remediation: "fix_input";
137
+ readonly en: "Invitation has already been used";
138
+ };
139
+ readonly "error.400.invitation_expired": {
140
+ readonly status: 400;
141
+ readonly params: readonly [];
142
+ readonly remediation: "contact_support";
143
+ readonly en: "Invitation has expired";
144
+ };
145
+ readonly "error.400.invitation_revoked": {
146
+ readonly status: 400;
147
+ readonly params: readonly [];
148
+ readonly remediation: "contact_support";
149
+ readonly en: "Invitation has been revoked";
150
+ };
151
+ readonly "error.400.validation_error": {
152
+ readonly status: 400;
153
+ readonly params: readonly [];
154
+ readonly remediation: "fix_input";
155
+ readonly en: "Validation error";
156
+ };
157
+ readonly "error.400.verification_failed": {
158
+ readonly status: 400;
159
+ readonly params: readonly [];
160
+ readonly remediation: "verify";
161
+ readonly en: "Verification failed";
162
+ };
163
+ readonly "error.400.verification_invalid_factor": {
164
+ readonly status: 400;
165
+ readonly params: readonly [];
166
+ readonly remediation: "verify";
167
+ readonly en: "This verification factor is not available";
168
+ };
169
+ readonly "error.400.workspace_slug_taken": {
170
+ readonly status: 400;
171
+ readonly params: readonly [];
172
+ readonly remediation: "fix_input";
173
+ readonly en: "Workspace slug is already taken";
174
+ };
175
+ readonly "error.401.unauthorized": {
176
+ readonly status: 401;
177
+ readonly params: readonly [];
178
+ readonly remediation: "reauthenticate";
179
+ readonly en: "Authentication required";
180
+ };
181
+ readonly "error.402.payment_required": {
182
+ readonly status: 402;
183
+ readonly params: readonly [];
184
+ readonly remediation: "retry";
185
+ readonly en: "Payment required";
186
+ };
187
+ readonly "error.403.forbidden": {
188
+ readonly status: 403;
189
+ readonly params: readonly [];
190
+ readonly remediation: "retry";
191
+ readonly en: "You do not have permission to perform this action";
192
+ };
193
+ readonly "error.403.forbidden_workspace": {
194
+ readonly status: 403;
195
+ readonly params: readonly [];
196
+ readonly remediation: "contact_support";
197
+ readonly en: "You do not have access to this workspace";
198
+ };
199
+ readonly "error.403.last_owner_cannot_be_removed": {
200
+ readonly status: 403;
201
+ readonly params: readonly [];
202
+ readonly remediation: "fix_input";
203
+ readonly en: "The last owner cannot be removed; transfer ownership first";
204
+ };
205
+ readonly "error.403.network_blocked": {
206
+ readonly status: 403;
207
+ readonly params: readonly [];
208
+ readonly remediation: "contact_support";
209
+ readonly en: "Requests from this network are not allowed";
210
+ };
211
+ readonly "error.403.verification_enrollment_required": {
212
+ readonly status: 403;
213
+ readonly params: readonly [];
214
+ readonly remediation: "verify";
215
+ readonly en: "Verification factor enrollment required";
216
+ };
217
+ readonly "error.403.verification_required": {
218
+ readonly status: 403;
219
+ readonly params: readonly [];
220
+ readonly remediation: "verify";
221
+ readonly en: "Additional verification required";
222
+ };
223
+ readonly "error.404.ad_not_found": {
224
+ readonly status: 404;
225
+ readonly params: readonly [];
226
+ readonly remediation: "retry";
227
+ readonly en: "Listing not found";
228
+ };
229
+ readonly "error.404.invitation_not_found": {
230
+ readonly status: 404;
231
+ readonly params: readonly [];
232
+ readonly remediation: "fix_input";
233
+ readonly en: "Invitation not found";
234
+ };
235
+ readonly "error.404.member_not_found": {
236
+ readonly status: 404;
237
+ readonly params: readonly [];
238
+ readonly remediation: "fix_input";
239
+ readonly en: "Member not found in this workspace";
240
+ };
241
+ readonly "error.404.not_found": {
242
+ readonly status: 404;
243
+ readonly params: readonly [];
244
+ readonly remediation: "retry";
245
+ readonly en: "Requested resource not found";
246
+ };
247
+ readonly "error.404.verification_challenge_not_found": {
248
+ readonly status: 404;
249
+ readonly params: readonly [];
250
+ readonly remediation: "verify";
251
+ readonly en: "Verification challenge not found or expired";
252
+ };
253
+ readonly "error.404.workspace_not_found": {
254
+ readonly status: 404;
255
+ readonly params: readonly [];
256
+ readonly remediation: "fix_input";
257
+ readonly en: "Workspace not found";
258
+ };
259
+ readonly "error.405.method_not_allowed": {
260
+ readonly status: 405;
261
+ readonly params: readonly [];
262
+ readonly remediation: "retry";
263
+ readonly en: "Method not allowed";
264
+ };
265
+ readonly "error.406.not_acceptable": {
266
+ readonly status: 406;
267
+ readonly params: readonly [];
268
+ readonly remediation: "retry";
269
+ readonly en: "Not acceptable";
270
+ };
271
+ readonly "error.408.request_timeout": {
272
+ readonly status: 408;
273
+ readonly params: readonly [];
274
+ readonly remediation: "retry";
275
+ readonly en: "Request timeout";
276
+ };
277
+ readonly "error.409.conflict": {
278
+ readonly status: 409;
279
+ readonly params: readonly [];
280
+ readonly remediation: "fix_input";
281
+ readonly en: "Resource already exists";
282
+ };
283
+ readonly "error.410.gone": {
284
+ readonly status: 410;
285
+ readonly params: readonly [];
286
+ readonly remediation: "retry";
287
+ readonly en: "Resource has been permanently removed";
288
+ };
289
+ readonly "error.413.payload_too_large": {
290
+ readonly status: 413;
291
+ readonly params: readonly [];
292
+ readonly remediation: "retry";
293
+ readonly en: "Request body is too large";
294
+ };
295
+ readonly "error.415.unsupported_media_type": {
296
+ readonly status: 415;
297
+ readonly params: readonly [];
298
+ readonly remediation: "retry";
299
+ readonly en: "Unsupported media type";
300
+ };
301
+ readonly "error.422.unprocessable_entity": {
302
+ readonly status: 422;
303
+ readonly params: readonly [];
304
+ readonly remediation: "wait_and_retry";
305
+ readonly en: "Unprocessable entity";
306
+ };
307
+ readonly "error.423.locked": {
308
+ readonly status: 423;
309
+ readonly params: readonly [];
310
+ readonly remediation: "wait_and_retry";
311
+ readonly en: "Resource is locked";
312
+ };
313
+ readonly "error.423.verification_locked": {
314
+ readonly status: 423;
315
+ readonly params: readonly [];
316
+ readonly remediation: "wait_and_retry";
317
+ readonly en: "Too many failed attempts — verification locked";
318
+ };
319
+ readonly "error.429.rate_limit": {
320
+ readonly status: 429;
321
+ readonly params: readonly ["retry_after_minutes"];
322
+ readonly remediation: "wait_and_retry";
323
+ readonly en: "Too many attempts. Try again in {retry_after_minutes} minutes.";
324
+ };
325
+ readonly "error.429.too_many_requests": {
326
+ readonly status: 429;
327
+ readonly params: readonly [];
328
+ readonly remediation: "wait_and_retry";
329
+ readonly en: "Too many requests. Please try again later.";
330
+ };
331
+ readonly "error.500.internal": {
332
+ readonly status: 500;
333
+ readonly params: readonly [];
334
+ readonly remediation: "contact_support";
335
+ readonly en: "Something went wrong";
336
+ };
337
+ };
338
+ export type WorkspacesErrorCode = keyof typeof WORKSPACES_ERRORS;
339
+ /** Every backend error code this module can surface, sorted. */
340
+ export declare const WORKSPACES_ERROR_CODES: readonly WorkspacesErrorCode[];
341
+ /**
342
+ * English fallback bundle — one string per backend key, so a `StapelApiError.code`
343
+ * never renders as a raw key. Merged UNDER the hand-polished UI copy in
344
+ * {@link authI18nBundleEn} (polish wins; this guarantees coverage).
345
+ */
346
+ export declare const workspacesErrorBundleEn: Record<WorkspacesErrorCode, string>;
347
+ //# sourceMappingURL=errors.gen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.gen.d.ts","sourceRoot":"","sources":["../../../src/i18n/generated/errors.gen.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,gBAAgB,GAChB,gBAAgB,GAChB,QAAQ,GACR,WAAW,GACX,iBAAiB,GACjB,KAAK,CAAC;AAEV,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDpB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAEjE,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,EAAE,SAAS,mBAAmB,EAqDhE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAqDvE,CAAC"}