@stapel/workspaces-react 0.8.0 → 0.9.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/dist/api/generated/schema.d.ts +107 -2
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/api/types.d.ts +7 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/workspacesApi.d.ts +3 -1
- package/dist/api/workspacesApi.d.ts.map +1 -1
- package/dist/api/workspacesApi.js +1 -0
- package/dist/api/workspacesApi.js.map +1 -1
- package/dist/default/MembersManager.js +2 -2
- package/dist/i18n/generated/errors.gen.d.ts +6 -0
- package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
- package/dist/i18n/generated/errors.gen.js +3 -0
- package/dist/i18n/generated/errors.gen.js.map +1 -1
- package/dist/i18n/generated/errors.ru.gen.d.ts.map +1 -1
- package/dist/i18n/generated/errors.ru.gen.js +1 -0
- package/dist/i18n/generated/errors.ru.gen.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model/mutations.d.ts +1 -1
- package/dist/model/mutations.js +1 -1
- package/dist/model/queries.d.ts +19 -1
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +25 -0
- package/dist/model/queries.js.map +1 -1
- package/dist/model/queryKeys.d.ts +1 -0
- package/dist/model/queryKeys.d.ts.map +1 -1
- package/dist/model/queryKeys.js +2 -1
- package/dist/model/queryKeys.js.map +1 -1
- package/llms.txt +6 -3
- package/manifest.json +26 -2
- package/package.json +2 -2
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +107 -2
- package/src/api/types.ts +8 -0
- package/src/api/workspacesApi.ts +6 -0
- package/src/default/MembersManager.tsx +2 -2
- package/src/i18n/generated/errors.gen.ts +3 -0
- package/src/i18n/generated/errors.json +9 -0
- package/src/i18n/generated/errors.ru.gen.ts +1 -0
- package/src/index.ts +1 -0
- package/src/model/mutations.ts +1 -1
- package/src/model/queries.ts +30 -0
- package/src/model/queryKeys.ts +3 -1
package/dist/model/queries.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InfiniteData, UseInfiniteQueryResult, UseQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { StapelApiError } from "@stapel/core";
|
|
3
|
-
import type { InvitationPage, InvitationPreview, InvitationsParams, MemberPage, MembersParams, RoleInfo, Workspace, WorkspaceList } from "../api/types.js";
|
|
3
|
+
import type { InvitationPage, InvitationPreview, InstanceShape, InvitationsParams, MemberPage, MembersParams, RoleInfo, Workspace, WorkspaceList } from "../api/types.js";
|
|
4
4
|
import type { CapabilityLevel } from "./stepUp.js";
|
|
5
5
|
/**
|
|
6
6
|
* Read hooks over the workspaces API. Staleness follows core's query defaults;
|
|
@@ -70,6 +70,24 @@ export declare function useInfiniteInvitations(workspaceId: string | null, filte
|
|
|
70
70
|
* {@link useWorkspaces} (IsAuthenticated endpoint, mounts at screen top).
|
|
71
71
|
*/
|
|
72
72
|
export declare function useRoles(): UseQueryResult<readonly RoleInfo[], StapelApiError>;
|
|
73
|
+
/**
|
|
74
|
+
* Deployment shape (GET /instance, unauthenticated).
|
|
75
|
+
*
|
|
76
|
+
* Answers the question a screen must ask BEFORE deciding what to show
|
|
77
|
+
* someone with no workspace: is this a closed deployment (`landing:
|
|
78
|
+
* "none"` — no workspace exists and none can be created) or a public cloud
|
|
79
|
+
* (`"personal"` — one exists and the screen can lead there)?
|
|
80
|
+
*
|
|
81
|
+
* Why a hook instead of a profile field: the reader is exactly the person
|
|
82
|
+
* who has no access — kicked out of their workspace, or having left it. So
|
|
83
|
+
* the request deliberately does NOT wait for a session, unlike {@link
|
|
84
|
+
* useRoles}: waiting would mean never answering the one person it exists for.
|
|
85
|
+
*
|
|
86
|
+
* The data is static per deployment — it only changes alongside the
|
|
87
|
+
* deployment itself, so the cache lives until page reload and is never
|
|
88
|
+
* refetched.
|
|
89
|
+
*/
|
|
90
|
+
export declare function useInstanceShape(): UseQueryResult<InstanceShape, StapelApiError>;
|
|
73
91
|
/**
|
|
74
92
|
* Public invitation preview (GET /invitations/{token}, AllowAny — org-program
|
|
75
93
|
* §B2): what the `/invite/{token}` page renders BEFORE any auth decision.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,sBAAsB,EACtB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,iBAAiB,CAAC;AAKzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,IAAI,cAAc,CAAC,aAAa,EAAE,cAAc,CAAC,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC,CAQ3C;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,CAAC,EAAE,aAAa,GACrB,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAS5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,CAAC,EAAE,iBAAiB,GACzB,cAAc,CAAC,cAAc,EAAE,cAAc,CAAC,CAShD;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,WAAW,CAAC,GACxD,sBAAsB,CACvB,YAAY,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,EAChD,cAAc,CACf,CAiBA;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,cAAc,CACxC,SAAS,QAAQ,EAAE,EACnB,cAAc,CACf,CAQA;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,cAAc,CAAC,iBAAiB,EAAE,cAAc,CAAC,CAOnD;AAED;qEACqE;AACrE,MAAM,WAAW,kBAAkB;IACjC;iEAC6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;wEACoE;IACpE,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,kBAAkB,CAU9E;AAED;6BAC6B;AAC7B,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC;gFAC4E;IAC5E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,MAAM,GACjB,cAAc,CAWhB"}
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"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"}
|
package/dist/model/queries.js
CHANGED
|
@@ -129,6 +129,31 @@ export function useRoles() {
|
|
|
129
129
|
enabled: sessionReady,
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Deployment shape (GET /instance, unauthenticated).
|
|
134
|
+
*
|
|
135
|
+
* Answers the question a screen must ask BEFORE deciding what to show
|
|
136
|
+
* someone with no workspace: is this a closed deployment (`landing:
|
|
137
|
+
* "none"` — no workspace exists and none can be created) or a public cloud
|
|
138
|
+
* (`"personal"` — one exists and the screen can lead there)?
|
|
139
|
+
*
|
|
140
|
+
* Why a hook instead of a profile field: the reader is exactly the person
|
|
141
|
+
* who has no access — kicked out of their workspace, or having left it. So
|
|
142
|
+
* the request deliberately does NOT wait for a session, unlike {@link
|
|
143
|
+
* useRoles}: waiting would mean never answering the one person it exists for.
|
|
144
|
+
*
|
|
145
|
+
* The data is static per deployment — it only changes alongside the
|
|
146
|
+
* deployment itself, so the cache lives until page reload and is never
|
|
147
|
+
* refetched.
|
|
148
|
+
*/
|
|
149
|
+
export function useInstanceShape() {
|
|
150
|
+
const api = useWorkspacesApi();
|
|
151
|
+
return useQuery({
|
|
152
|
+
queryKey: workspacesQueryKeys.instance(),
|
|
153
|
+
queryFn: () => api.getInstanceShape(),
|
|
154
|
+
staleTime: Infinity,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
132
157
|
/**
|
|
133
158
|
* Public invitation preview (GET /invitations/{token}, AllowAny — org-program
|
|
134
159
|
* §B2): what the `/invite/{token}` page renders BEFORE any auth decision.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAMnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,7 @@ export declare const workspacesQueryKeys: {
|
|
|
15
15
|
InvitationsParams
|
|
16
16
|
];
|
|
17
17
|
roles(): readonly ["workspaces", "roles"];
|
|
18
|
+
instance(): readonly ["workspaces", "instance"];
|
|
18
19
|
invitationPreview(token: string): readonly ["workspaces", "invitation-preview", string];
|
|
19
20
|
};
|
|
20
21
|
//# sourceMappingURL=queryKeys.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryKeys.d.ts","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWxE,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;IACzE,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,GACpB,SAAS,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7D,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACjF,eAAe,CACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,GACxB,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACrE,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,SAAS;QACV,YAAY;QACZ,aAAa;QACb,MAAM;QACN,UAAU;QACV,iBAAiB;KAClB,CAAC;IACF,KAAK,IAAI,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC1C,iBAAiB,CACf,KAAK,EAAE,MAAM,GACZ,SAAS,CAAC,YAAY,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"queryKeys.d.ts","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAWxE,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;IACzE,WAAW,CACT,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,GACpB,SAAS,CAAC,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7D,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC;IACjF,eAAe,CACb,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,iBAAiB,GACxB,SAAS,CAAC,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACrE,mBAAmB,CACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,iBAAiB,GACzB,SAAS;QACV,YAAY;QACZ,aAAa;QACb,MAAM;QACN,UAAU;QACV,iBAAiB;KAClB,CAAC;IACF,KAAK,IAAI,SAAS,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAC1C,QAAQ,IAAI,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAChD,iBAAiB,CACf,KAAK,EAAE,MAAM,GACZ,SAAS,CAAC,YAAY,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;CAmC1D,CAAC"}
|
package/dist/model/queryKeys.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Namespaced TanStack Query keys (frontend-standard §2 —
|
|
2
|
+
* Namespaced TanStack Query keys (frontend-standard §2 — namespaced keys).
|
|
3
3
|
* Everything under the `"workspaces"` root so a host can invalidate the whole
|
|
4
4
|
* module or match a single resource. Persist scope is per-user via core's query
|
|
5
5
|
* runtime (`setPersistUser`). Explicit tuple return types satisfy
|
|
@@ -34,6 +34,7 @@ export const workspacesQueryKeys = {
|
|
|
34
34
|
filters,
|
|
35
35
|
],
|
|
36
36
|
roles: () => [ROOT, "roles"],
|
|
37
|
+
instance: () => [ROOT, "instance"],
|
|
37
38
|
// NOTE: the key carries the invite TOKEN (a secret). Core's query persist
|
|
38
39
|
// scope is per-user and the preview response is already public-by-design
|
|
39
40
|
// (masked email only) — but hosts logging query keys should treat this one
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,YAAqB,CAAC;AAEnC,MAAM,CAAC,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"queryKeys.js","sourceRoot":"","sources":["../../src/model/queryKeys.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,IAAI,GAAG,YAAqB,CAAC;AAEnC,MAAM,CAAC,MAAM,mBAAmB,GA6B5B;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,kEAAkE;IAClE,uEAAuE;IACvE,OAAO,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC;IACxD,WAAW,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,CAAC;IAC5E,0EAA0E;IAC1E,qEAAqE;IACrE,WAAW,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC;IAChE,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI;QACJ,aAAa;QACb,WAAW;QACX,MAAM;KACP;IACD,2EAA2E;IAC3E,uEAAuE;IACvE,yDAAyD;IACzD,mBAAmB,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI;QACJ,aAAa;QACb,WAAW;QACX,UAAU;QACV,OAAO;KACR;IACD,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC;IAClC,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,gBAAgB;IAChB,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,oBAAoB,EAAE,KAAK,CAAC;CAClE,CAAC"}
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# @stapel/workspaces-react 0.
|
|
1
|
+
# @stapel/workspaces-react 0.9.0
|
|
2
2
|
|
|
3
|
-
Headless React flow pair for stapel-workspaces (contract >=0.
|
|
3
|
+
Headless React flow pair for stapel-workspaces (contract >=0.18 <0.19) — business + state, zero visual opinion.
|
|
4
4
|
Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
|
|
5
5
|
verification-403 interception, i18n engine, analytics facade, TanStack Query layer.
|
|
6
6
|
|
|
@@ -26,6 +26,7 @@ Request/response schema names are in manifest.json + the generated types.
|
|
|
26
26
|
Paths are relative to `/workspaces/api/v1/`.
|
|
27
27
|
- workspaces_api_v1_create: POST /
|
|
28
28
|
- workspaces_api_v1_destroy: DELETE /{workspace_id}
|
|
29
|
+
- workspaces_api_v1_instance_retrieve: GET /instance
|
|
29
30
|
- workspaces_api_v1_internal_members_retrieve: GET /internal/{workspace_id}/members/{user_id}
|
|
30
31
|
- workspaces_api_v1_internal_users_personal_create: POST /internal/users/{user_id}/personal
|
|
31
32
|
- workspaces_api_v1_invitations_accept_create: POST /invitations/accept
|
|
@@ -52,6 +53,7 @@ Paths are relative to `/workspaces/api/v1/`.
|
|
|
52
53
|
- useCreateWorkspace (mutation) → createWorkspace
|
|
53
54
|
- useDeclineInvitation (mutation) → declineInvitation
|
|
54
55
|
- useDeleteWorkspace (mutation) → deleteWorkspace
|
|
56
|
+
- useInstanceShape (query) → getInstanceShape
|
|
55
57
|
- useInvitationPreview (query) → getInvitationPreview
|
|
56
58
|
- useInvitations (query) → listInvitations
|
|
57
59
|
- useInviteMembers (mutation) → inviteMembers
|
|
@@ -68,7 +70,7 @@ Paths are relative to `/workspaces/api/v1/`.
|
|
|
68
70
|
- useWorkspaces (query) → listWorkspaces
|
|
69
71
|
|
|
70
72
|
## Errors (render t(code, params); UX from remediation)
|
|
71
|
-
|
|
73
|
+
61 keys (full catalog: manifest.json §errors). By remediation: fix_input 29 · retry 12 · contact_support 7 · wait_and_retry 6 · verify 5 · reauthenticate 2.
|
|
72
74
|
Param-bearing keys (interpolation slots matter):
|
|
73
75
|
- error.400.field.blank [400] → fix_input {field}
|
|
74
76
|
- error.400.field.does_not_exist [400] → fix_input {field}
|
|
@@ -84,6 +86,7 @@ Param-bearing keys (interpolation slots matter):
|
|
|
84
86
|
- error.402.member_limit_reached [402] → fix_input {limit}
|
|
85
87
|
- error.403.membership_suspended [403] → fix_input {reason}
|
|
86
88
|
- error.403.missing_capability [403] → contact_support {capability}
|
|
89
|
+
- error.403.role_exceeds_inviter_rank [403] → fix_input {role}
|
|
87
90
|
- error.429.rate_limit [429] → wait_and_retry {retry_after_minutes}
|
|
88
91
|
|
|
89
92
|
## Analytics events (typed; defineEvent → events.json, drift-gated)
|
package/manifest.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$generated": "by scripts/gen-manifest.mjs — do not edit; drift-gated (pnpm gen:manifest:check)",
|
|
3
3
|
"package": "@stapel/workspaces-react",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"backend": {
|
|
6
6
|
"module": "stapel-workspaces",
|
|
7
|
-
"contract": ">=0.
|
|
7
|
+
"contract": ">=0.18 <0.19"
|
|
8
8
|
},
|
|
9
9
|
"layers": [
|
|
10
10
|
"api",
|
|
@@ -32,6 +32,13 @@
|
|
|
32
32
|
"request": null,
|
|
33
33
|
"response": null
|
|
34
34
|
},
|
|
35
|
+
"workspaces_api_v1_instance_retrieve": {
|
|
36
|
+
"method": "GET",
|
|
37
|
+
"path": "/workspaces/api/v1/instance",
|
|
38
|
+
"tag": "Workspaces",
|
|
39
|
+
"request": null,
|
|
40
|
+
"response": "InstanceShapeResponse"
|
|
41
|
+
},
|
|
35
42
|
"workspaces_api_v1_internal_members_retrieve": {
|
|
36
43
|
"method": "GET",
|
|
37
44
|
"path": "/workspaces/api/v1/internal/{workspace_id}/members/{user_id}",
|
|
@@ -222,6 +229,14 @@
|
|
|
222
229
|
]
|
|
223
230
|
]
|
|
224
231
|
},
|
|
232
|
+
"useInstanceShape": {
|
|
233
|
+
"kind": "query",
|
|
234
|
+
"operation": "getInstanceShape",
|
|
235
|
+
"queryKey": [
|
|
236
|
+
"workspaces",
|
|
237
|
+
"instance"
|
|
238
|
+
]
|
|
239
|
+
},
|
|
225
240
|
"useInvitationPreview": {
|
|
226
241
|
"kind": "query",
|
|
227
242
|
"operation": "getInvitationPreview",
|
|
@@ -604,6 +619,13 @@
|
|
|
604
619
|
"params": [],
|
|
605
620
|
"remediation": "contact_support"
|
|
606
621
|
},
|
|
622
|
+
"error.403.role_exceeds_inviter_rank": {
|
|
623
|
+
"status": 403,
|
|
624
|
+
"params": [
|
|
625
|
+
"role"
|
|
626
|
+
],
|
|
627
|
+
"remediation": "fix_input"
|
|
628
|
+
},
|
|
607
629
|
"error.403.verification_enrollment_required": {
|
|
608
630
|
"status": 403,
|
|
609
631
|
"params": [],
|
|
@@ -863,6 +885,7 @@
|
|
|
863
885
|
"error.403.membership_suspended",
|
|
864
886
|
"error.403.missing_capability",
|
|
865
887
|
"error.403.network_blocked",
|
|
888
|
+
"error.403.role_exceeds_inviter_rank",
|
|
866
889
|
"error.403.verification_enrollment_required",
|
|
867
890
|
"error.403.verification_required",
|
|
868
891
|
"error.404.ad_not_found",
|
|
@@ -989,6 +1012,7 @@
|
|
|
989
1012
|
"useDeleteWorkspace",
|
|
990
1013
|
"useFlow",
|
|
991
1014
|
"useInfiniteInvitations",
|
|
1015
|
+
"useInstanceShape",
|
|
992
1016
|
"useInvitationPreview",
|
|
993
1017
|
"useInvitations",
|
|
994
1018
|
"useInviteMembers",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stapel/workspaces-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Headless React flow pair for stapel-workspaces: typed API client, TanStack Query hooks, flow machines, headless components, and i18n keys. Zero visual opinion.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -82,8 +82,8 @@
|
|
|
82
82
|
"size-limit": "^11.2.0",
|
|
83
83
|
"typescript": "^5.8.3",
|
|
84
84
|
"vitest": "^3.2.4",
|
|
85
|
+
"@stapel/core": "^0.10.0",
|
|
85
86
|
"@stapel/showcase": "^0.2.0",
|
|
86
|
-
"@stapel/core": "^0.9.0",
|
|
87
87
|
"@stapel/tokens": "^0.5.0"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
@@ -403,6 +403,27 @@ export interface paths {
|
|
|
403
403
|
patch?: never;
|
|
404
404
|
trace?: never;
|
|
405
405
|
};
|
|
406
|
+
"/workspaces/api/v1/instance": {
|
|
407
|
+
parameters: {
|
|
408
|
+
query?: never;
|
|
409
|
+
header?: never;
|
|
410
|
+
path?: never;
|
|
411
|
+
cookie?: never;
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
* @description Instance shape: how a street signup lands (personal | none) and whether self-serve registration is open. Public, unauthenticated — the screen a kicked/left member sees depends on it.
|
|
415
|
+
*
|
|
416
|
+
* **Permissions:** `AllowAny`
|
|
417
|
+
*/
|
|
418
|
+
get: operations["workspaces_api_v1_instance_retrieve"];
|
|
419
|
+
put?: never;
|
|
420
|
+
post?: never;
|
|
421
|
+
delete?: never;
|
|
422
|
+
options?: never;
|
|
423
|
+
head?: never;
|
|
424
|
+
patch?: never;
|
|
425
|
+
trace?: never;
|
|
426
|
+
};
|
|
406
427
|
"/workspaces/api/v1/internal/{workspace_id}/members/{user_id}": {
|
|
407
428
|
parameters: {
|
|
408
429
|
query?: never;
|
|
@@ -585,6 +606,38 @@ export interface paths {
|
|
|
585
606
|
export type webhooks = Record<string, never>;
|
|
586
607
|
export interface components {
|
|
587
608
|
schemas: {
|
|
609
|
+
/**
|
|
610
|
+
* @description Как развёрнут ЭТОТ инстанс — то, что клиенту нужно знать ДО того, как
|
|
611
|
+
* он решит, что показать человеку без пространства.
|
|
612
|
+
*
|
|
613
|
+
* Ось ``landing`` (``STREET_LANDING_MODE``) существовала с 03.08.2026, но
|
|
614
|
+
* жила только в окружении бэкенда: наружу не отдавалась ничем, и отличить
|
|
615
|
+
* закрытый контур от публичного облака на клиенте было НЕЧЕМ.
|
|
616
|
+
*
|
|
617
|
+
* Почему это не косметика. Экран, который видит человек, выброшенный из
|
|
618
|
+
* Спейса (или вышедший сам), в этих двух мирах разный по существу:
|
|
619
|
+
*
|
|
620
|
+
* * ``none`` — закрытый контур: своего пространства у человека нет и
|
|
621
|
+
* взяться неоткуда. Честный экран говорит «вы не участник, попросите
|
|
622
|
+
* приглашение» и никуда не зовёт;
|
|
623
|
+
* * ``personal`` — публичное облако: у него есть собственное
|
|
624
|
+
* пространство, и туда можно вести.
|
|
625
|
+
*
|
|
626
|
+
* Показать «создайте встречу» тому, кому инстанс её создать не даст, —
|
|
627
|
+
* это тупик, нарисованный кнопкой.
|
|
628
|
+
*/
|
|
629
|
+
InstanceShapeResponse: {
|
|
630
|
+
/**
|
|
631
|
+
* @description С чем приземляется человек «с улицы»
|
|
632
|
+
* @example personal
|
|
633
|
+
*/
|
|
634
|
+
landing: string;
|
|
635
|
+
/**
|
|
636
|
+
* @description Можно ли завести учётку самому
|
|
637
|
+
* @example True
|
|
638
|
+
*/
|
|
639
|
+
registration_open: boolean;
|
|
640
|
+
};
|
|
588
641
|
/** @description Get-or-create result for a user's personal workspace (service-to-service). */
|
|
589
642
|
InternalPersonalWorkspaceResponse: {
|
|
590
643
|
/**
|
|
@@ -692,9 +745,19 @@ export interface components {
|
|
|
692
745
|
* @example 0192a...
|
|
693
746
|
*/
|
|
694
747
|
invited_by_id?: string | null;
|
|
748
|
+
/**
|
|
749
|
+
* @description Name hint typed for this invitee at invite time, if any; null otherwise
|
|
750
|
+
* @example Ada Lovelace
|
|
751
|
+
*/
|
|
752
|
+
display_name?: string | null;
|
|
695
753
|
};
|
|
696
754
|
/** @description Invite payload. */
|
|
697
755
|
MemberInviteRequest: {
|
|
756
|
+
/**
|
|
757
|
+
* @description Name hint for the invitee (this invite's "Имя" field), applied to every email in this request. Optional — an invite without one behaves exactly as before. NOT written into stapel-profiles directly (that store is the invitee's own): held on the invitation, copied onto the member at accept time, and shown only until stapel-profiles has a real name for the person
|
|
758
|
+
* @example Ada Lovelace
|
|
759
|
+
*/
|
|
760
|
+
display_name?: string | null;
|
|
698
761
|
/**
|
|
699
762
|
* @description One or more emails to invite
|
|
700
763
|
* @example [
|
|
@@ -793,6 +856,11 @@ export interface components {
|
|
|
793
856
|
suspended_at?: string | null;
|
|
794
857
|
/** @description Why the membership is suspended (canonical value no_mfa); null while active */
|
|
795
858
|
suspension_reason?: string | null;
|
|
859
|
+
/**
|
|
860
|
+
* @description Best-effort display name — a live lookup in stapel-profiles when it is installed and has one, else the name typed at invite/provision time (never both, never invented when neither exists). Null when nobody has one yet
|
|
861
|
+
* @example Ada Lovelace
|
|
862
|
+
*/
|
|
863
|
+
display_name?: string | null;
|
|
796
864
|
};
|
|
797
865
|
PaginatedInvitationResponseList: {
|
|
798
866
|
items: components["schemas"]["InvitationResponse"][];
|
|
@@ -874,9 +942,19 @@ export interface components {
|
|
|
874
942
|
/** @description Server-generated initial password — returned exactly ONCE, only when the request omitted password. Store it or hand it to the user now; it cannot be re-fetched. A credential: never log it */
|
|
875
943
|
generated_password?: string | null;
|
|
876
944
|
};
|
|
877
|
-
/** @description
|
|
945
|
+
/** @description The effective role registry (builtin four + STAPEL_WORKSPACES overlay). */
|
|
878
946
|
RoleListResponse: {
|
|
947
|
+
/** @description One entry per effective role, descending rank */
|
|
879
948
|
roles?: components["schemas"]["RoleResponse"][];
|
|
949
|
+
/**
|
|
950
|
+
* @description Step-up level per namespaced capability string, builtin ``members.provision`` / ``members.password.reset`` / ``workspace.security.manage`` plus the deployment's ``STAPEL_WORKSPACES["CAPABILITY_LEVELS"]`` overlay. A capability absent from this map is ``"standard"`` — the client-side default. Lets a frontend stop hardcoding its own copy of this registry
|
|
951
|
+
* @example {
|
|
952
|
+
* "members.provision": "high"
|
|
953
|
+
* }
|
|
954
|
+
*/
|
|
955
|
+
capability_levels?: {
|
|
956
|
+
[key: string]: string;
|
|
957
|
+
};
|
|
880
958
|
};
|
|
881
959
|
/** @description One role of the effective registry (builtin + STAPEL_WORKSPACES overlay). */
|
|
882
960
|
RoleResponse: {
|
|
@@ -943,9 +1021,17 @@ export interface components {
|
|
|
943
1021
|
*/
|
|
944
1022
|
type?: string;
|
|
945
1023
|
};
|
|
946
|
-
/** @description
|
|
1024
|
+
/** @description The caller's own workspace list. */
|
|
947
1025
|
WorkspaceListResponse: {
|
|
1026
|
+
/** @description The caller's active memberships (empty for a guest — see is_guest) */
|
|
948
1027
|
workspaces?: components["schemas"]["WorkspaceResponse"][];
|
|
1028
|
+
/** @description True when the caller holds NO active mandate anywhere (permissions.is_guest) — the wire form of the mandate-model vardict's guest predicate (2026-08-03), so a frontend can render the "incomplete dashboard" without re-deriving it from workspaces == [] */
|
|
1029
|
+
is_guest?: boolean;
|
|
1030
|
+
/**
|
|
1031
|
+
* @description Which workspace a client should open when the person has expressed no choice — the instance's STAPEL_WORKSPACES["DEFAULT_WORKSPACE_ID"], echoed back ONLY when the caller actually holds an active membership in it, else "". Exists because clients that had to guess guessed badly: meettoday took `workspaces[0]` off a list ordered by last access, so a person in two spaces landed wherever they happened to have been last (measured 2026-08-06 as "the owner cannot see his own invitations" — they were in the OTHER space). A default, not a cage: an explicit choice still wins
|
|
1032
|
+
* @example a8bba7ae-5d2e-43e5-9911-0553e7df50b3
|
|
1033
|
+
*/
|
|
1034
|
+
default_workspace_id?: string;
|
|
949
1035
|
};
|
|
950
1036
|
/** @description Workspace details. */
|
|
951
1037
|
WorkspaceResponse: {
|
|
@@ -1368,6 +1454,25 @@ export interface operations {
|
|
|
1368
1454
|
};
|
|
1369
1455
|
};
|
|
1370
1456
|
};
|
|
1457
|
+
workspaces_api_v1_instance_retrieve: {
|
|
1458
|
+
parameters: {
|
|
1459
|
+
query?: never;
|
|
1460
|
+
header?: never;
|
|
1461
|
+
path?: never;
|
|
1462
|
+
cookie?: never;
|
|
1463
|
+
};
|
|
1464
|
+
requestBody?: never;
|
|
1465
|
+
responses: {
|
|
1466
|
+
200: {
|
|
1467
|
+
headers: {
|
|
1468
|
+
[name: string]: unknown;
|
|
1469
|
+
};
|
|
1470
|
+
content: {
|
|
1471
|
+
"application/json": components["schemas"]["InstanceShapeResponse"];
|
|
1472
|
+
};
|
|
1473
|
+
};
|
|
1474
|
+
};
|
|
1475
|
+
};
|
|
1371
1476
|
workspaces_api_v1_internal_members_retrieve: {
|
|
1372
1477
|
parameters: {
|
|
1373
1478
|
query?: never;
|
package/src/api/types.ts
CHANGED
|
@@ -68,6 +68,14 @@ export type RoleInfo = Schemas["RoleResponse"];
|
|
|
68
68
|
/** GET /roles 200 body — the effective role registry, rank-descending. */
|
|
69
69
|
export type RoleList = Schemas["RoleListResponse"];
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Deployment shape: what a person landing "off the street" gets, and
|
|
73
|
+
* whether self-serve signup is open. A property of the INSTANCE, not of a
|
|
74
|
+
* workspace — and not a setting the customer can toggle: it's fixed at
|
|
75
|
+
* deployment time.
|
|
76
|
+
*/
|
|
77
|
+
export type InstanceShape = Schemas["InstanceShapeResponse"];
|
|
78
|
+
|
|
71
79
|
// ── documented corrections (drf-spectacular under-describes) ──────────────────
|
|
72
80
|
|
|
73
81
|
/**
|
package/src/api/workspacesApi.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
InvitationAccept,
|
|
15
15
|
InvitationClaim,
|
|
16
16
|
InvitationPreview,
|
|
17
|
+
InstanceShape,
|
|
17
18
|
RoleList,
|
|
18
19
|
Workspace,
|
|
19
20
|
WorkspaceCreate,
|
|
@@ -171,6 +172,9 @@ export interface WorkspacesApi {
|
|
|
171
172
|
/** The effective role registry (builtin + deployment overlay), for
|
|
172
173
|
* RoleSelect-class UI — capability strings verbatim, rank-descending. */
|
|
173
174
|
listRoles(): Promise<RoleList>;
|
|
175
|
+
|
|
176
|
+
/** Instance shape (GET /instance, unauthenticated). */
|
|
177
|
+
getInstanceShape(): Promise<InstanceShape>;
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
export function createWorkspacesApi(client: StapelClient): WorkspacesApi {
|
|
@@ -284,5 +288,7 @@ export function createWorkspacesApi(client: StapelClient): WorkspacesApi {
|
|
|
284
288
|
),
|
|
285
289
|
|
|
286
290
|
listRoles: () => client.get("/roles"),
|
|
291
|
+
|
|
292
|
+
getInstanceShape: () => client.get("/instance"),
|
|
287
293
|
};
|
|
288
294
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `<MembersManager/>` — default skin for the "members & roles" settings
|
|
3
|
-
* screen (owner directive:
|
|
4
|
-
*
|
|
3
|
+
* screen (owner directive: workspace settings — name/members/roles/
|
|
4
|
+
* invites). Built entirely on this pair's EXISTING `Members` headless
|
|
5
5
|
* wrapper (`useMembers`/`useInviteMembers`/`useUpdateMemberRole`/
|
|
6
6
|
* `useRemoveMember`) — no new backend surface.
|
|
7
7
|
*
|
|
@@ -72,6 +72,7 @@ export const WORKSPACES_ERRORS = {
|
|
|
72
72
|
"error.403.membership_suspended": { status: 403, params: ["reason"], remediation: "fix_input", en: "Your membership in this workspace is suspended ({reason})" },
|
|
73
73
|
"error.403.missing_capability": { status: 403, params: ["capability"], remediation: "contact_support", en: "Your role does not include the {capability} capability in this workspace" },
|
|
74
74
|
"error.403.network_blocked": { status: 403, params: [], remediation: "contact_support", en: "Requests from this network are not allowed" },
|
|
75
|
+
"error.403.role_exceeds_inviter_rank": { status: 403, params: ["role"], remediation: "fix_input", en: "You cannot grant a role that outranks your own ({role})" },
|
|
75
76
|
"error.403.verification_enrollment_required": { status: 403, params: [], remediation: "verify", en: "Verification factor enrollment required" },
|
|
76
77
|
"error.403.verification_required": { status: 403, params: [], remediation: "verify", en: "Additional verification required" },
|
|
77
78
|
"error.404.ad_not_found": { status: 404, params: [], remediation: "retry", en: "Listing not found" },
|
|
@@ -138,6 +139,7 @@ export const WORKSPACES_ERROR_CODES: readonly WorkspacesErrorCode[] = [
|
|
|
138
139
|
"error.403.membership_suspended",
|
|
139
140
|
"error.403.missing_capability",
|
|
140
141
|
"error.403.network_blocked",
|
|
142
|
+
"error.403.role_exceeds_inviter_rank",
|
|
141
143
|
"error.403.verification_enrollment_required",
|
|
142
144
|
"error.403.verification_required",
|
|
143
145
|
"error.404.ad_not_found",
|
|
@@ -206,6 +208,7 @@ export const workspacesErrorBundleEn: Record<WorkspacesErrorCode, string> = {
|
|
|
206
208
|
"error.403.membership_suspended": "Your membership in this workspace is suspended ({reason})",
|
|
207
209
|
"error.403.missing_capability": "Your role does not include the {capability} capability in this workspace",
|
|
208
210
|
"error.403.network_blocked": "Requests from this network are not allowed",
|
|
211
|
+
"error.403.role_exceeds_inviter_rank": "You cannot grant a role that outranks your own ({role})",
|
|
209
212
|
"error.403.verification_enrollment_required": "Verification factor enrollment required",
|
|
210
213
|
"error.403.verification_required": "Additional verification required",
|
|
211
214
|
"error.404.ad_not_found": "Listing not found",
|
|
@@ -290,6 +290,15 @@
|
|
|
290
290
|
"remediation": "contact_support",
|
|
291
291
|
"en": "Requests from this network are not allowed"
|
|
292
292
|
},
|
|
293
|
+
{
|
|
294
|
+
"code": "error.403.role_exceeds_inviter_rank",
|
|
295
|
+
"status": 403,
|
|
296
|
+
"params": [
|
|
297
|
+
"role"
|
|
298
|
+
],
|
|
299
|
+
"remediation": "fix_input",
|
|
300
|
+
"en": "You cannot grant a role that outranks your own ({role})"
|
|
301
|
+
},
|
|
293
302
|
{
|
|
294
303
|
"code": "error.403.verification_enrollment_required",
|
|
295
304
|
"status": 403,
|
|
@@ -49,6 +49,7 @@ export const workspacesErrorBundleRu: Record<WorkspacesErrorCode, string> = {
|
|
|
49
49
|
"error.403.membership_suspended": "Ваше членство в этом рабочем пространстве приостановлено ({reason})",
|
|
50
50
|
"error.403.missing_capability": "Ваша роль не включает право {capability} в этом рабочем пространстве",
|
|
51
51
|
"error.403.network_blocked": "Запросы из этой сети не разрешены.",
|
|
52
|
+
"error.403.role_exceeds_inviter_rank": "Вы не можете выдать роль, которая превышает вашу собственную ({role})",
|
|
52
53
|
"error.403.verification_enrollment_required": "Требуется регистрация фактора подтверждения.",
|
|
53
54
|
"error.403.verification_required": "Требуется дополнительная проверка",
|
|
54
55
|
"error.404.ad_not_found": "Объявление не найдено",
|
package/src/index.ts
CHANGED
package/src/model/mutations.ts
CHANGED
|
@@ -22,7 +22,7 @@ import { useWorkspacesApi } from "./context.js";
|
|
|
22
22
|
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Write hooks (frontend-standard §2 —
|
|
25
|
+
* Write hooks (frontend-standard §2 — mutations invalidate on success). Each mutation
|
|
26
26
|
* invalidates exactly the server state it can move. Membership and ownership are
|
|
27
27
|
* server truth (roles gate access in other services via the membership cache),
|
|
28
28
|
* so NONE of these are optimistic (frontend-core-architecture §2.6: optimistic
|
package/src/model/queries.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type { StapelApiError } from "@stapel/core";
|
|
|
9
9
|
import type {
|
|
10
10
|
InvitationPage,
|
|
11
11
|
InvitationPreview,
|
|
12
|
+
InstanceShape,
|
|
12
13
|
InvitationsParams,
|
|
13
14
|
MemberPage,
|
|
14
15
|
MembersParams,
|
|
@@ -173,6 +174,35 @@ export function useRoles(): UseQueryResult<
|
|
|
173
174
|
});
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Deployment shape (GET /instance, unauthenticated).
|
|
179
|
+
*
|
|
180
|
+
* Answers the question a screen must ask BEFORE deciding what to show
|
|
181
|
+
* someone with no workspace: is this a closed deployment (`landing:
|
|
182
|
+
* "none"` — no workspace exists and none can be created) or a public cloud
|
|
183
|
+
* (`"personal"` — one exists and the screen can lead there)?
|
|
184
|
+
*
|
|
185
|
+
* Why a hook instead of a profile field: the reader is exactly the person
|
|
186
|
+
* who has no access — kicked out of their workspace, or having left it. So
|
|
187
|
+
* the request deliberately does NOT wait for a session, unlike {@link
|
|
188
|
+
* useRoles}: waiting would mean never answering the one person it exists for.
|
|
189
|
+
*
|
|
190
|
+
* The data is static per deployment — it only changes alongside the
|
|
191
|
+
* deployment itself, so the cache lives until page reload and is never
|
|
192
|
+
* refetched.
|
|
193
|
+
*/
|
|
194
|
+
export function useInstanceShape(): UseQueryResult<
|
|
195
|
+
InstanceShape,
|
|
196
|
+
StapelApiError
|
|
197
|
+
> {
|
|
198
|
+
const api = useWorkspacesApi();
|
|
199
|
+
return useQuery({
|
|
200
|
+
queryKey: workspacesQueryKeys.instance(),
|
|
201
|
+
queryFn: () => api.getInstanceShape(),
|
|
202
|
+
staleTime: Infinity,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
176
206
|
/**
|
|
177
207
|
* Public invitation preview (GET /invitations/{token}, AllowAny — org-program
|
|
178
208
|
* §B2): what the `/invite/{token}` page renders BEFORE any auth decision.
|
package/src/model/queryKeys.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { InvitationsParams, MembersParams } from "../api/types.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Namespaced TanStack Query keys (frontend-standard §2 —
|
|
4
|
+
* Namespaced TanStack Query keys (frontend-standard §2 — namespaced keys).
|
|
5
5
|
* Everything under the `"workspaces"` root so a host can invalidate the whole
|
|
6
6
|
* module or match a single resource. Persist scope is per-user via core's query
|
|
7
7
|
* runtime (`setPersistUser`). Explicit tuple return types satisfy
|
|
@@ -34,6 +34,7 @@ export const workspacesQueryKeys: {
|
|
|
34
34
|
InvitationsParams,
|
|
35
35
|
];
|
|
36
36
|
roles(): readonly ["workspaces", "roles"];
|
|
37
|
+
instance(): readonly ["workspaces", "instance"];
|
|
37
38
|
invitationPreview(
|
|
38
39
|
token: string
|
|
39
40
|
): readonly ["workspaces", "invitation-preview", string];
|
|
@@ -65,6 +66,7 @@ export const workspacesQueryKeys: {
|
|
|
65
66
|
filters,
|
|
66
67
|
],
|
|
67
68
|
roles: () => [ROOT, "roles"],
|
|
69
|
+
instance: () => [ROOT, "instance"],
|
|
68
70
|
// NOTE: the key carries the invite TOKEN (a secret). Core's query persist
|
|
69
71
|
// scope is per-user and the preview response is already public-by-design
|
|
70
72
|
// (masked email only) — but hosts logging query keys should treat this one
|