@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.
- package/CHANGELOG.md +60 -0
- package/LICENSE +21 -0
- package/MODULE.md +54 -0
- package/README.md +73 -0
- package/dist/api/extensions.d.ts +8 -0
- package/dist/api/extensions.d.ts.map +1 -0
- package/dist/api/extensions.js +8 -0
- package/dist/api/extensions.js.map +1 -0
- package/dist/api/types.d.ts +51 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/workspacesApi.d.ts +43 -0
- package/dist/api/workspacesApi.d.ts.map +1 -0
- package/dist/api/workspacesApi.js +31 -0
- package/dist/api/workspacesApi.js.map +1 -0
- package/dist/flows/errors.d.ts +12 -0
- package/dist/flows/errors.d.ts.map +1 -0
- package/dist/flows/errors.js +13 -0
- package/dist/flows/errors.js.map +1 -0
- package/dist/flows/generated/flows.gen.d.ts +19 -0
- package/dist/flows/generated/flows.gen.d.ts.map +1 -0
- package/dist/flows/generated/flows.gen.js +23 -0
- package/dist/flows/generated/flows.gen.js.map +1 -0
- package/dist/headless/AcceptInvitation.d.ts +39 -0
- package/dist/headless/AcceptInvitation.d.ts.map +1 -0
- package/dist/headless/AcceptInvitation.js +27 -0
- package/dist/headless/AcceptInvitation.js.map +1 -0
- package/dist/headless/Members.d.ts +47 -0
- package/dist/headless/Members.d.ts.map +1 -0
- package/dist/headless/Members.js +50 -0
- package/dist/headless/Members.js.map +1 -0
- package/dist/headless/WorkspaceList.d.ts +38 -0
- package/dist/headless/WorkspaceList.d.ts.map +1 -0
- package/dist/headless/WorkspaceList.js +33 -0
- package/dist/headless/WorkspaceList.js.map +1 -0
- package/dist/headless/WorkspacesProvider.d.ts +18 -0
- package/dist/headless/WorkspacesProvider.d.ts.map +1 -0
- package/dist/headless/WorkspacesProvider.js +17 -0
- package/dist/headless/WorkspacesProvider.js.map +1 -0
- package/dist/i18n/errorsMap.d.ts +10 -0
- package/dist/i18n/errorsMap.d.ts.map +1 -0
- package/dist/i18n/errorsMap.js +20 -0
- package/dist/i18n/errorsMap.js.map +1 -0
- package/dist/i18n/generated/errors.gen.d.ts +347 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.gen.js +177 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts +9 -0
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -0
- package/dist/i18n/generated/errors.ru.gen.js +61 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -0
- package/dist/i18n/keys.d.ts +55 -0
- package/dist/i18n/keys.d.ts.map +1 -0
- package/dist/i18n/keys.js +76 -0
- package/dist/i18n/keys.js.map +1 -0
- package/dist/i18n/ru.d.ts +28 -0
- package/dist/i18n/ru.d.ts.map +1 -0
- package/dist/i18n/ru.js +49 -0
- package/dist/i18n/ru.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/model/context.d.ts +14 -0
- package/dist/model/context.d.ts.map +1 -0
- package/dist/model/context.js +21 -0
- package/dist/model/context.js.map +1 -0
- package/dist/model/mutations.d.ts +55 -0
- package/dist/model/mutations.d.ts.map +1 -0
- package/dist/model/mutations.js +138 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/queries.d.ts +21 -0
- package/dist/model/queries.d.ts.map +1 -0
- package/dist/model/queries.js +41 -0
- package/dist/model/queries.js.map +1 -0
- package/dist/model/queryKeys.d.ts +7 -0
- package/dist/model/queryKeys.d.ts.map +1 -0
- package/dist/model/queryKeys.js +15 -0
- package/dist/model/queryKeys.js.map +1 -0
- package/dist/model/runtime.d.ts +26 -0
- package/dist/model/runtime.d.ts.map +1 -0
- package/dist/model/runtime.js +18 -0
- package/dist/model/runtime.js.map +1 -0
- package/llms.txt +95 -0
- package/manifest.json +705 -0
- package/package.json +85 -0
- package/src/analytics/generated/events.json +7 -0
- package/src/api/extensions.ts +7 -0
- package/src/api/types.ts +58 -0
- package/src/api/workspacesApi.ts +139 -0
- package/src/flows/errors.ts +16 -0
- package/src/flows/generated/flows.gen.ts +38 -0
- package/src/flows/generated/flows.json +1 -0
- package/src/headless/AcceptInvitation.tsx +53 -0
- package/src/headless/Members.tsx +89 -0
- package/src/headless/WorkspaceList.tsx +58 -0
- package/src/headless/WorkspacesProvider.tsx +25 -0
- package/src/i18n/errorsMap.ts +31 -0
- package/src/i18n/generated/errors.gen.ts +208 -0
- package/src/i18n/generated/errors.json +394 -0
- package/src/i18n/generated/errors.ru.gen.ts +67 -0
- package/src/i18n/keys.ts +83 -0
- package/src/i18n/ru.ts +53 -0
- package/src/index.ts +113 -0
- package/src/model/context.tsx +29 -0
- package/src/model/mutations.ts +196 -0
- package/src/model/queries.ts +51 -0
- package/src/model/queryKeys.ts +20 -0
- package/src/model/runtime.ts +46 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Context } from "react";
|
|
2
|
+
import type { Analytics } from "@stapel/core";
|
|
3
|
+
import type { WorkspacesApi } from "../api/workspacesApi.js";
|
|
4
|
+
import type { WorkspacesRuntime } from "./runtime.js";
|
|
5
|
+
/**
|
|
6
|
+
* The wired WorkspacesRuntime shared through React context by
|
|
7
|
+
* `<WorkspacesProvider>`. Hooks in `model/` and `headless/` read the singletons
|
|
8
|
+
* from here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const WorkspacesRuntimeContext: Context<WorkspacesRuntime | null>;
|
|
11
|
+
export declare function useWorkspacesRuntime(): WorkspacesRuntime;
|
|
12
|
+
export declare function useWorkspacesApi(): WorkspacesApi;
|
|
13
|
+
export declare function useWorkspacesAnalytics(): Analytics | null;
|
|
14
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/model/context.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,OAAO,CAAC,iBAAiB,GAAG,IAAI,CACxB,CAAC;AAEhD,wBAAgB,oBAAoB,IAAI,iBAAiB,CAMxD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,wBAAgB,sBAAsB,IAAI,SAAS,GAAG,IAAI,CAEzD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* The wired WorkspacesRuntime shared through React context by
|
|
4
|
+
* `<WorkspacesProvider>`. Hooks in `model/` and `headless/` read the singletons
|
|
5
|
+
* from here.
|
|
6
|
+
*/
|
|
7
|
+
export const WorkspacesRuntimeContext = createContext(null);
|
|
8
|
+
export function useWorkspacesRuntime() {
|
|
9
|
+
const runtime = useContext(WorkspacesRuntimeContext);
|
|
10
|
+
if (runtime === null) {
|
|
11
|
+
throw new Error("Workspaces hooks must be used within a <WorkspacesProvider>");
|
|
12
|
+
}
|
|
13
|
+
return runtime;
|
|
14
|
+
}
|
|
15
|
+
export function useWorkspacesApi() {
|
|
16
|
+
return useWorkspacesRuntime().api;
|
|
17
|
+
}
|
|
18
|
+
export function useWorkspacesAnalytics() {
|
|
19
|
+
return useWorkspacesRuntime().analytics;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/model/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAMlD;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,aAAa,CAA2B,IAAI,CAAC,CAAC;AAEhD,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAG,UAAU,CAAC,wBAAwB,CAAC,CAAC;IACrD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,oBAAoB,EAAE,CAAC,GAAG,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,oBAAoB,EAAE,CAAC,SAAS,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { StapelApiError } from "@stapel/core";
|
|
3
|
+
import type { Member, MemberInvite, MemberInviteResult, InvitationAccept, Workspace, WorkspaceCreate, WorkspaceRole, WorkspaceUpdate } from "../api/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Write hooks (frontend-standard §2 — "мутации с инвалидацией"). Each mutation
|
|
6
|
+
* invalidates exactly the server state it can move. Membership and ownership are
|
|
7
|
+
* server truth (roles gate access in other services via the membership cache),
|
|
8
|
+
* so NONE of these are optimistic (frontend-core-architecture §2.6: optimistic
|
|
9
|
+
* is for local-echo UX, never for flows with server truth).
|
|
10
|
+
*
|
|
11
|
+
* Options are built as typed `UseMutationOptions` objects (not call-site
|
|
12
|
+
* generics) so `void` stays in type-reference position, which
|
|
13
|
+
* `no-invalid-void-type` permits. Hooks that act on one workspace take its id as
|
|
14
|
+
* a parameter (the mutation variable then carries only the payload).
|
|
15
|
+
*/
|
|
16
|
+
/** Create a workspace (owner-seeded) — refreshes the workspace list. */
|
|
17
|
+
export declare function useCreateWorkspace(): UseMutationResult<Workspace, StapelApiError, WorkspaceCreate>;
|
|
18
|
+
/**
|
|
19
|
+
* Partially update a workspace — writes the fresh row into its detail cache and
|
|
20
|
+
* refreshes the list (name / slug may have changed there too).
|
|
21
|
+
*/
|
|
22
|
+
export declare function useUpdateWorkspace(workspaceId: string): UseMutationResult<Workspace, StapelApiError, WorkspaceUpdate>;
|
|
23
|
+
/** Soft-delete a workspace (owner only) — drops its detail cache + refreshes the list. */
|
|
24
|
+
export declare function useDeleteWorkspace(): UseMutationResult<void, StapelApiError, string>;
|
|
25
|
+
/**
|
|
26
|
+
* Invite one or more emails to a workspace (admin+). Server truth — no optimism.
|
|
27
|
+
* A bad role or missing email surfaces as a localizable `StapelApiError`
|
|
28
|
+
* (`error.400.invalid_role`). Refreshes the member list (pending invites show
|
|
29
|
+
* there).
|
|
30
|
+
*/
|
|
31
|
+
export declare function useInviteMembers(workspaceId: string): UseMutationResult<MemberInviteResult, StapelApiError, MemberInvite>;
|
|
32
|
+
/** The variable for {@link useUpdateMemberRole}: which member, which new role. */
|
|
33
|
+
export interface MemberRoleChange {
|
|
34
|
+
readonly userId: string;
|
|
35
|
+
readonly role: WorkspaceRole;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Change a member's role (admin+; the backend guards owner grants and the
|
|
39
|
+
* last-owner invariant, surfacing `error.403.last_owner_cannot_be_removed`).
|
|
40
|
+
* Refreshes the member list.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useUpdateMemberRole(workspaceId: string): UseMutationResult<Member, StapelApiError, MemberRoleChange>;
|
|
43
|
+
/**
|
|
44
|
+
* Remove a member (admin+; the last owner is protected by the backend). The
|
|
45
|
+
* variable is the member's `userId`. Refreshes the member list.
|
|
46
|
+
*/
|
|
47
|
+
export declare function useRemoveMember(workspaceId: string): UseMutationResult<void, StapelApiError, string>;
|
|
48
|
+
/**
|
|
49
|
+
* Accept an invitation by its token — the caller joins the workspace. A dead
|
|
50
|
+
* token surfaces a localizable `StapelApiError` (`error.400.invitation_expired`
|
|
51
|
+
* / `error.400.invitation_revoked` / `error.400.invitation_already_used`).
|
|
52
|
+
* Refreshes the workspace list (the new membership appears there).
|
|
53
|
+
*/
|
|
54
|
+
export declare function useAcceptInvitation(): UseMutationResult<Member, StapelApiError, InvitationAccept>;
|
|
55
|
+
//# sourceMappingURL=mutations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../../src/model/mutations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,aAAa,EACb,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAIzB;;;;;;;;;;;GAWG;AAEH,wEAAwE;AACxE,wBAAgB,kBAAkB,IAAI,iBAAiB,CACrD,SAAS,EACT,cAAc,EACd,eAAe,CAChB,CAaA;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAAC,SAAS,EAAE,cAAc,EAAE,eAAe,CAAC,CAiB/D;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,IAAI,iBAAiB,CACrD,IAAI,EACJ,cAAc,EACd,MAAM,CACP,CAeA;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAAC,kBAAkB,EAAE,cAAc,EAAE,YAAY,CAAC,CAgBrE;AAED,kFAAkF;AAClF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAAC,MAAM,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAa7D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,GAClB,iBAAiB,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,CAYjD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,iBAAiB,CACtD,MAAM,EACN,cAAc,EACd,gBAAgB,CACjB,CAYA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { useWorkspacesApi } from "./context.js";
|
|
3
|
+
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
4
|
+
/**
|
|
5
|
+
* Write hooks (frontend-standard §2 — "мутации с инвалидацией"). Each mutation
|
|
6
|
+
* invalidates exactly the server state it can move. Membership and ownership are
|
|
7
|
+
* server truth (roles gate access in other services via the membership cache),
|
|
8
|
+
* so NONE of these are optimistic (frontend-core-architecture §2.6: optimistic
|
|
9
|
+
* is for local-echo UX, never for flows with server truth).
|
|
10
|
+
*
|
|
11
|
+
* Options are built as typed `UseMutationOptions` objects (not call-site
|
|
12
|
+
* generics) so `void` stays in type-reference position, which
|
|
13
|
+
* `no-invalid-void-type` permits. Hooks that act on one workspace take its id as
|
|
14
|
+
* a parameter (the mutation variable then carries only the payload).
|
|
15
|
+
*/
|
|
16
|
+
/** Create a workspace (owner-seeded) — refreshes the workspace list. */
|
|
17
|
+
export function useCreateWorkspace() {
|
|
18
|
+
const api = useWorkspacesApi();
|
|
19
|
+
const queryClient = useQueryClient();
|
|
20
|
+
const options = {
|
|
21
|
+
mutationFn: (body) => api.createWorkspace(body),
|
|
22
|
+
onSuccess: () => {
|
|
23
|
+
void queryClient.invalidateQueries({
|
|
24
|
+
queryKey: workspacesQueryKeys.list(),
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
return useMutation(options);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Partially update a workspace — writes the fresh row into its detail cache and
|
|
32
|
+
* refreshes the list (name / slug may have changed there too).
|
|
33
|
+
*/
|
|
34
|
+
export function useUpdateWorkspace(workspaceId) {
|
|
35
|
+
const api = useWorkspacesApi();
|
|
36
|
+
const queryClient = useQueryClient();
|
|
37
|
+
const options = {
|
|
38
|
+
mutationFn: (patch) => api.updateWorkspace(workspaceId, patch),
|
|
39
|
+
onSuccess: (updated) => {
|
|
40
|
+
queryClient.setQueryData(workspacesQueryKeys.detail(workspaceId), updated);
|
|
41
|
+
void queryClient.invalidateQueries({
|
|
42
|
+
queryKey: workspacesQueryKeys.list(),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
return useMutation(options);
|
|
47
|
+
}
|
|
48
|
+
/** Soft-delete a workspace (owner only) — drops its detail cache + refreshes the list. */
|
|
49
|
+
export function useDeleteWorkspace() {
|
|
50
|
+
const api = useWorkspacesApi();
|
|
51
|
+
const queryClient = useQueryClient();
|
|
52
|
+
const options = {
|
|
53
|
+
mutationFn: (workspaceId) => api.deleteWorkspace(workspaceId),
|
|
54
|
+
onSuccess: (_result, workspaceId) => {
|
|
55
|
+
queryClient.removeQueries({
|
|
56
|
+
queryKey: workspacesQueryKeys.detail(workspaceId),
|
|
57
|
+
});
|
|
58
|
+
void queryClient.invalidateQueries({
|
|
59
|
+
queryKey: workspacesQueryKeys.list(),
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
return useMutation(options);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Invite one or more emails to a workspace (admin+). Server truth — no optimism.
|
|
67
|
+
* A bad role or missing email surfaces as a localizable `StapelApiError`
|
|
68
|
+
* (`error.400.invalid_role`). Refreshes the member list (pending invites show
|
|
69
|
+
* there).
|
|
70
|
+
*/
|
|
71
|
+
export function useInviteMembers(workspaceId) {
|
|
72
|
+
const api = useWorkspacesApi();
|
|
73
|
+
const queryClient = useQueryClient();
|
|
74
|
+
const options = {
|
|
75
|
+
mutationFn: (body) => api.inviteMembers(workspaceId, body),
|
|
76
|
+
onSuccess: () => {
|
|
77
|
+
void queryClient.invalidateQueries({
|
|
78
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
return useMutation(options);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Change a member's role (admin+; the backend guards owner grants and the
|
|
86
|
+
* last-owner invariant, surfacing `error.403.last_owner_cannot_be_removed`).
|
|
87
|
+
* Refreshes the member list.
|
|
88
|
+
*/
|
|
89
|
+
export function useUpdateMemberRole(workspaceId) {
|
|
90
|
+
const api = useWorkspacesApi();
|
|
91
|
+
const queryClient = useQueryClient();
|
|
92
|
+
const options = {
|
|
93
|
+
mutationFn: ({ userId, role }) => api.updateMemberRole(workspaceId, userId, { role }),
|
|
94
|
+
onSuccess: () => {
|
|
95
|
+
void queryClient.invalidateQueries({
|
|
96
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
return useMutation(options);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Remove a member (admin+; the last owner is protected by the backend). The
|
|
104
|
+
* variable is the member's `userId`. Refreshes the member list.
|
|
105
|
+
*/
|
|
106
|
+
export function useRemoveMember(workspaceId) {
|
|
107
|
+
const api = useWorkspacesApi();
|
|
108
|
+
const queryClient = useQueryClient();
|
|
109
|
+
const options = {
|
|
110
|
+
mutationFn: (userId) => api.removeMember(workspaceId, userId),
|
|
111
|
+
onSuccess: () => {
|
|
112
|
+
void queryClient.invalidateQueries({
|
|
113
|
+
queryKey: workspacesQueryKeys.members(workspaceId),
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
return useMutation(options);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Accept an invitation by its token — the caller joins the workspace. A dead
|
|
121
|
+
* token surfaces a localizable `StapelApiError` (`error.400.invitation_expired`
|
|
122
|
+
* / `error.400.invitation_revoked` / `error.400.invitation_already_used`).
|
|
123
|
+
* Refreshes the workspace list (the new membership appears there).
|
|
124
|
+
*/
|
|
125
|
+
export function useAcceptInvitation() {
|
|
126
|
+
const api = useWorkspacesApi();
|
|
127
|
+
const queryClient = useQueryClient();
|
|
128
|
+
const options = {
|
|
129
|
+
mutationFn: (body) => api.acceptInvitation(body),
|
|
130
|
+
onSuccess: () => {
|
|
131
|
+
void queryClient.invalidateQueries({
|
|
132
|
+
queryKey: workspacesQueryKeys.list(),
|
|
133
|
+
});
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
return useMutation(options);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=mutations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/model/mutations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { UseQueryResult } from "@tanstack/react-query";
|
|
2
|
+
import type { StapelApiError } from "@stapel/core";
|
|
3
|
+
import type { MemberList, Workspace, WorkspaceList } from "../api/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read hooks over the workspaces API. Staleness follows core's query defaults;
|
|
6
|
+
* override per call site via a page that needs fresher data. Keys are
|
|
7
|
+
* namespaced (see `workspacesQueryKeys`).
|
|
8
|
+
*/
|
|
9
|
+
/** The caller's workspaces — their accepted memberships (GET /). */
|
|
10
|
+
export declare function useWorkspaces(): UseQueryResult<WorkspaceList, StapelApiError>;
|
|
11
|
+
/**
|
|
12
|
+
* A single workspace by id (GET /{id}). Disabled until a `workspaceId` is
|
|
13
|
+
* given, so a detail hook can mount before a selection exists.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useWorkspace(workspaceId: string | null): UseQueryResult<Workspace, StapelApiError>;
|
|
16
|
+
/**
|
|
17
|
+
* A workspace's members (GET /{id}/members). Disabled until a `workspaceId` is
|
|
18
|
+
* given.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useMembers(workspaceId: string | null): UseQueryResult<MemberList, StapelApiError>;
|
|
21
|
+
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI5E;;;;GAIG;AAEH,oEAAoE;AACpE,wBAAgB,aAAa,IAAI,cAAc,CAAC,aAAa,EAAE,cAAc,CAAC,CAM7E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC,CAO3C;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAO5C"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { useWorkspacesApi } from "./context.js";
|
|
3
|
+
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
4
|
+
/**
|
|
5
|
+
* Read hooks over the workspaces API. Staleness follows core's query defaults;
|
|
6
|
+
* override per call site via a page that needs fresher data. Keys are
|
|
7
|
+
* namespaced (see `workspacesQueryKeys`).
|
|
8
|
+
*/
|
|
9
|
+
/** The caller's workspaces — their accepted memberships (GET /). */
|
|
10
|
+
export function useWorkspaces() {
|
|
11
|
+
const api = useWorkspacesApi();
|
|
12
|
+
return useQuery({
|
|
13
|
+
queryKey: workspacesQueryKeys.list(),
|
|
14
|
+
queryFn: () => api.listWorkspaces(),
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A single workspace by id (GET /{id}). Disabled until a `workspaceId` is
|
|
19
|
+
* given, so a detail hook can mount before a selection exists.
|
|
20
|
+
*/
|
|
21
|
+
export function useWorkspace(workspaceId) {
|
|
22
|
+
const api = useWorkspacesApi();
|
|
23
|
+
return useQuery({
|
|
24
|
+
queryKey: workspacesQueryKeys.detail(workspaceId ?? ""),
|
|
25
|
+
queryFn: () => api.getWorkspace(workspaceId),
|
|
26
|
+
enabled: workspaceId !== null && workspaceId !== "",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A workspace's members (GET /{id}/members). Disabled until a `workspaceId` is
|
|
31
|
+
* given.
|
|
32
|
+
*/
|
|
33
|
+
export function useMembers(workspaceId) {
|
|
34
|
+
const api = useWorkspacesApi();
|
|
35
|
+
return useQuery({
|
|
36
|
+
queryKey: workspacesQueryKeys.members(workspaceId ?? ""),
|
|
37
|
+
queryFn: () => api.listMembers(workspaceId),
|
|
38
|
+
enabled: workspaceId !== null && workspaceId !== "",
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAIjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;GAIG;AAEH,oEAAoE;AACpE,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,mBAAmB,CAAC,IAAI,EAAE;QACpC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE;KACpC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,WAA0B;IAE1B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,mBAAmB,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC;QACvD,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,WAAqB,CAAC;QACtD,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,EAAE;KACpD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,WAA0B;IAE1B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,mBAAmB,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;QACxD,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,WAAqB,CAAC;QACrD,OAAO,EAAE,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,EAAE;KACpD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const workspacesQueryKeys: {
|
|
2
|
+
readonly all: readonly ["workspaces"];
|
|
3
|
+
list(): readonly ["workspaces", "list"];
|
|
4
|
+
detail(workspaceId: string): readonly ["workspaces", "detail", string];
|
|
5
|
+
members(workspaceId: string): readonly ["workspaces", "members", string];
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=queryKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryKeys.d.ts","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,mBAAmB,EAAE;IAChC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IACtC,IAAI,IAAI,SAAS,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACvE,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;CAM1E,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespaced TanStack Query keys (frontend-standard §2 — "ключи неймспейснуты").
|
|
3
|
+
* Everything under the `"workspaces"` root so a host can invalidate the whole
|
|
4
|
+
* module or match a single resource. Persist scope is per-user via core's query
|
|
5
|
+
* runtime (`setPersistUser`). Explicit tuple return types satisfy
|
|
6
|
+
* `--isolatedDeclarations`. One entry per read-operation.
|
|
7
|
+
*/
|
|
8
|
+
const ROOT = "workspaces";
|
|
9
|
+
export const workspacesQueryKeys = {
|
|
10
|
+
all: [ROOT],
|
|
11
|
+
list: () => [ROOT, "list"],
|
|
12
|
+
detail: (workspaceId) => [ROOT, "detail", workspaceId],
|
|
13
|
+
members: (workspaceId) => [ROOT, "members", workspaceId],
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=queryKeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,YAAqB,CAAC;AAEnC,MAAM,CAAC,MAAM,mBAAmB,GAK5B;IACF,GAAG,EAAE,CAAC,IAAI,CAAC;IACX,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC;IACtD,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC;CACzD,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Analytics, StapelClient } from "@stapel/core";
|
|
2
|
+
import type { WorkspacesApi } from "../api/workspacesApi.js";
|
|
3
|
+
/**
|
|
4
|
+
* The wired workspaces runtime — builds a {@link StapelClient} and the pair's
|
|
5
|
+
* API over it. The returned `client` is what the host injects into core's
|
|
6
|
+
* `StapelConfigProvider` (as the default or the `"workspaces"` module client),
|
|
7
|
+
* preserving the client-injection fork seam (frontend-standard §7.2). Auth
|
|
8
|
+
* token/refresh and the verification-403 seam are supplied by the host's auth
|
|
9
|
+
* runtime on the shared client — this pair does not re-implement them.
|
|
10
|
+
*/
|
|
11
|
+
export interface WorkspacesRuntime {
|
|
12
|
+
readonly client: StapelClient;
|
|
13
|
+
readonly api: WorkspacesApi;
|
|
14
|
+
readonly analytics: Analytics | null;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateWorkspacesRuntimeOptions {
|
|
17
|
+
/** e.g. `/workspaces/api/` or `https://app.example.com/workspaces/api/`. */
|
|
18
|
+
readonly baseUrl: string;
|
|
19
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
20
|
+
readonly credentials?: RequestCredentials;
|
|
21
|
+
readonly analytics?: Analytics | null;
|
|
22
|
+
/** Extra headers merged into every request (e.g. a tenant id). */
|
|
23
|
+
readonly defaultHeaders?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
export declare function createWorkspacesRuntime(options: CreateWorkspacesRuntimeOptions): WorkspacesRuntime;
|
|
26
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/model/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,8BAA8B;IAC7C,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,8BAA8B,GACtC,iBAAiB,CAcnB"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createStapelClient } from "@stapel/core";
|
|
2
|
+
import { createWorkspacesApi } from "../api/workspacesApi.js";
|
|
3
|
+
export function createWorkspacesRuntime(options) {
|
|
4
|
+
const analytics = options.analytics ?? null;
|
|
5
|
+
const client = createStapelClient({
|
|
6
|
+
baseUrl: options.baseUrl,
|
|
7
|
+
...(options.fetch !== undefined ? { fetch: options.fetch } : {}),
|
|
8
|
+
...(options.credentials !== undefined
|
|
9
|
+
? { credentials: options.credentials }
|
|
10
|
+
: {}),
|
|
11
|
+
...(options.defaultHeaders !== undefined
|
|
12
|
+
? { defaultHeaders: options.defaultHeaders }
|
|
13
|
+
: {}),
|
|
14
|
+
});
|
|
15
|
+
const api = createWorkspacesApi(client);
|
|
16
|
+
return { client, api, analytics };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/model/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA2B9D,MAAM,UAAU,uBAAuB,CACrC,OAAuC;IAEvC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAC5C,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;YACtC,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS;YACtC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE;YAC5C,CAAC,CAAC,EAAE,CAAC;KACR,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACpC,CAAC"}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @stapel/workspaces-react 0.1.0
|
|
2
|
+
|
|
3
|
+
Headless React flow pair for stapel-workspaces (contract >=0.3 <0.4) — business + state, zero visual opinion.
|
|
4
|
+
Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
|
|
5
|
+
verification-403 interception, i18n engine, analytics facade, TanStack Query layer.
|
|
6
|
+
|
|
7
|
+
## The one right way (do this, the rest is a review/lint smell)
|
|
8
|
+
- No raw fetch/axios. The client is injected via <WorkspacesProvider>/StapelConfigProvider;
|
|
9
|
+
every hook and flow already carries auth, refresh, and the error envelope.
|
|
10
|
+
- Render errors, never try/catch them: a flow's state carries FlowError{code,params};
|
|
11
|
+
render `t(code, params)` and branch on `explainWorkspacesError(code)` remediation.
|
|
12
|
+
- Server state = the use* hooks (query layer); keys come only from workspacesQueryKeys.
|
|
13
|
+
- User strings = i18n keys (registerWorkspacesI18n); never string literals.
|
|
14
|
+
- Sign-in UI = a headless flow component; copy it (shadcn-style) to restyle.
|
|
15
|
+
|
|
16
|
+
## Layers
|
|
17
|
+
api (typed client) · model (hooks, session) · flows (machines) · headless · i18n
|
|
18
|
+
|
|
19
|
+
## Documented flows (flows.json — canonical id, steps, endpoints)
|
|
20
|
+
|
|
21
|
+
## Operations (typed; use the named op, never a path string)
|
|
22
|
+
Request/response schema names are in manifest.json + the generated types.
|
|
23
|
+
- workspaces_api_create: POST /workspaces/api/
|
|
24
|
+
- workspaces_api_destroy: DELETE /workspaces/api/{workspace_id}
|
|
25
|
+
- workspaces_api_internal_members_retrieve: GET /workspaces/api/internal/{workspace_id}/members/{user_id}
|
|
26
|
+
- workspaces_api_internal_users_personal_create: POST /workspaces/api/internal/users/{user_id}/personal
|
|
27
|
+
- workspaces_api_invitations_accept_create: POST /workspaces/api/invitations/accept
|
|
28
|
+
- workspaces_api_members_destroy: DELETE /workspaces/api/{workspace_id}/members/{user_id}
|
|
29
|
+
- workspaces_api_members_invite_create: POST /workspaces/api/{workspace_id}/members/invite
|
|
30
|
+
- workspaces_api_members_partial_update: PATCH /workspaces/api/{workspace_id}/members/{user_id}
|
|
31
|
+
- workspaces_api_members_retrieve: GET /workspaces/api/{workspace_id}/members
|
|
32
|
+
- workspaces_api_partial_update: PATCH /workspaces/api/{workspace_id}
|
|
33
|
+
- workspaces_api_retrieve: GET /workspaces/api/
|
|
34
|
+
- workspaces_api_retrieve_2: GET /workspaces/api/{workspace_id}
|
|
35
|
+
|
|
36
|
+
## Query hooks (server state; keys come only from the key factory)
|
|
37
|
+
- useAcceptInvitation (mutation) → acceptInvitation
|
|
38
|
+
- useCreateWorkspace (mutation) → createWorkspace
|
|
39
|
+
- useDeleteWorkspace (mutation) → deleteWorkspace
|
|
40
|
+
- useInviteMembers (mutation) → inviteMembers
|
|
41
|
+
- useMembers (query) → listMembers
|
|
42
|
+
- useRemoveMember (mutation) → removeMember
|
|
43
|
+
- useUpdateMemberRole (mutation) → updateMemberRole
|
|
44
|
+
- useUpdateWorkspace (mutation) → updateWorkspace
|
|
45
|
+
- useWorkspace (query) → getWorkspace
|
|
46
|
+
- useWorkspaces (query) → listWorkspaces
|
|
47
|
+
|
|
48
|
+
## Errors (render t(code, params); UX from remediation)
|
|
49
|
+
52 keys (full catalog: manifest.json §errors). By remediation: fix_input 24 · retry 12 · contact_support 5 · verify 5 · wait_and_retry 5 · reauthenticate 1.
|
|
50
|
+
Param-bearing keys (interpolation slots matter):
|
|
51
|
+
- error.400.field.blank [400] → fix_input {field}
|
|
52
|
+
- error.400.field.does_not_exist [400] → fix_input {field}
|
|
53
|
+
- error.400.field.invalid [400] → fix_input {field}
|
|
54
|
+
- error.400.field.invalid_choice [400] → fix_input {field}
|
|
55
|
+
- error.400.field.max_length [400] → fix_input {field,max_length}
|
|
56
|
+
- error.400.field.max_value [400] → fix_input {field,max_value}
|
|
57
|
+
- error.400.field.min_length [400] → fix_input {field,min_length}
|
|
58
|
+
- error.400.field.min_value [400] → fix_input {field,min_value}
|
|
59
|
+
- error.400.field.null [400] → fix_input {field}
|
|
60
|
+
- error.400.field.required [400] → fix_input {field}
|
|
61
|
+
- error.400.field.unique [400] → fix_input {field}
|
|
62
|
+
- error.429.rate_limit [429] → wait_and_retry {retry_after_minutes}
|
|
63
|
+
|
|
64
|
+
## Analytics events (typed; defineEvent → events.json, drift-gated)
|
|
65
|
+
- (no app defineEvent() in this pair — its analytic events are the
|
|
66
|
+
auto-instrumented flow funnels below)
|
|
67
|
+
|
|
68
|
+
## Flow funnels (auto-instrumented: flow.<id>.<step> {phase})
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
// Typed event + tracked() click (the one right way; §3.1).
|
|
72
|
+
const planSelected = defineEvent({
|
|
73
|
+
name: "pricing.plan.selected",
|
|
74
|
+
description: "User picked a plan",
|
|
75
|
+
props: { plan: prop.oneOf(["free", "pro", "team"], "Plan code") },
|
|
76
|
+
});
|
|
77
|
+
const { tracked } = useTracked();
|
|
78
|
+
<Button onClick={tracked(planSelected, { plan }, startCheckout)} />
|
|
79
|
+
// A click that STEPS a flow machine is already instrumented — mark it
|
|
80
|
+
// data-analytics="flow" instead; tracked() on top double-counts (§3.2).
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Demos (defineDemo → manifest.demos; compiled, linted, rendered examples)
|
|
84
|
+
- workspaces.accept → <AcceptInvitation> [default] demo/AcceptInvitation.demo.tsx
|
|
85
|
+
- workspaces.list → <WorkspaceList> [default] demo/WorkspaceList.demo.tsx
|
|
86
|
+
- workspaces.members → <Members> [default] demo/Members.demo.tsx
|
|
87
|
+
- workspaces.provider → <WorkspacesProvider> [default] demo/Workspaces.demo.tsx
|
|
88
|
+
Each source file is the canonical usage snippet (open the default variant).
|
|
89
|
+
|
|
90
|
+
## Snippets
|
|
91
|
+
```tsx
|
|
92
|
+
// Error rendering + remediation branch (one pattern for every pair).
|
|
93
|
+
const r = explainWorkspacesError(err.code); // 'wait_and_retry' | 'verify' | ...
|
|
94
|
+
return <Alert action={r}>{t(err.code, err.params)}</Alert>;
|
|
95
|
+
```
|