@stapel/workspaces-react 0.5.0 → 0.6.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 +26 -0
- package/dist/model/queries.d.ts +19 -5
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +26 -7
- package/dist/model/queries.js.map +1 -1
- package/llms.txt +1 -1
- package/manifest.json +1 -1
- package/package.json +4 -4
- package/src/analytics/generated/events.json +1 -1
- package/src/model/queries.ts +26 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# @stapel/workspaces-react
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 6ef6c44: Gate top-level "the caller's own …" query hooks on `@stapel/core`'s new
|
|
8
|
+
`useActiveSessionReady()` (owner-diagnosed live incident, 2026-07-17): a hook
|
|
9
|
+
with no natural `enabled` condition of its own (`useWorkspaces`, `useWallet`,
|
|
10
|
+
`useTransactions`, `useSubscription`, `useNotificationFeed`/
|
|
11
|
+
`useInfiniteNotificationFeed`, `useCalendar`/`useEvents`/`useAvailability`,
|
|
12
|
+
`useRecordings`) fires the instant a component mounts — which used to race a
|
|
13
|
+
session still bootstrapping and read a live one as "expired". Detail hooks
|
|
14
|
+
keyed by an id (`useWorkspace`/`useMembers`/`useEvent`/`useRecording`) now
|
|
15
|
+
ALSO gate on session readiness in addition to their existing non-empty-id
|
|
16
|
+
check, since an id can be known synchronously (e.g. a URL param) before the
|
|
17
|
+
session settles.
|
|
18
|
+
|
|
19
|
+
Deliberately NOT gated: `useCatalog` (billing) and `useLanguages` (profiles,
|
|
20
|
+
unaffected by this changeset but worth noting for symmetry) — both are
|
|
21
|
+
public reference lists a signed-out visitor legitimately needs.
|
|
22
|
+
|
|
23
|
+
Zero manual wiring at any call site: `useActiveSessionReady()` reads
|
|
24
|
+
whichever `SessionManager` a session-owning module (e.g.
|
|
25
|
+
`@stapel/auth-react`'s `createAuthRuntime`) registered as "active", and
|
|
26
|
+
defaults to `true` (never blocks) when no such module exists in the host at
|
|
27
|
+
all.
|
|
28
|
+
|
|
3
29
|
## 0.5.0
|
|
4
30
|
|
|
5
31
|
### Minor Changes
|
package/dist/model/queries.d.ts
CHANGED
|
@@ -6,18 +6,32 @@ import type { MemberPage, MembersParams, Workspace, WorkspaceList } from "../api
|
|
|
6
6
|
* override per call site via a page that needs fresher data. Keys are
|
|
7
7
|
* namespaced (see `workspacesQueryKeys`).
|
|
8
8
|
*/
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* The caller's workspaces — their accepted memberships (GET /).
|
|
11
|
+
*
|
|
12
|
+
* Gated on {@link useActiveSessionReady} (owner-diagnosed live incident,
|
|
13
|
+
* 2026-07-17): unlike {@link useWorkspace}/{@link useMembers} below (both
|
|
14
|
+
* naturally disabled until a `workspaceId` is picked), this is the top-level
|
|
15
|
+
* list hook with nothing else to gate it — it fires the instant a component
|
|
16
|
+
* mounts. Without the session ready-gate this is exactly the shape of hook
|
|
17
|
+
* that raced a session still bootstrapping (e.g. right after a QR
|
|
18
|
+
* `session_share` scan set fresh cookies this JS runtime hadn't caught up
|
|
19
|
+
* to yet) and read a live session as "expired" before it had a chance to
|
|
20
|
+
* resolve — zero manual `enabled` wiring needed at each call site by design.
|
|
21
|
+
*/
|
|
10
22
|
export declare function useWorkspaces(): UseQueryResult<WorkspaceList, StapelApiError>;
|
|
11
23
|
/**
|
|
12
24
|
* A single workspace by id (GET /{id}). Disabled until a `workspaceId` is
|
|
13
|
-
* given, so a detail hook can mount before a selection exists
|
|
25
|
+
* given, so a detail hook can mount before a selection exists — AND until
|
|
26
|
+
* the session is ready (a `workspaceId` can be known synchronously, e.g.
|
|
27
|
+
* from a URL param, before the session has finished bootstrapping).
|
|
14
28
|
*/
|
|
15
29
|
export declare function useWorkspace(workspaceId: string | null): UseQueryResult<Workspace, StapelApiError>;
|
|
16
30
|
/**
|
|
17
31
|
* A page of a workspace's members (GET /{id}/members, anchor-paginated).
|
|
18
|
-
* Disabled until a `workspaceId` is given
|
|
19
|
-
*
|
|
20
|
-
* (default limit 100).
|
|
32
|
+
* Disabled until a `workspaceId` is given (and the session is ready — see
|
|
33
|
+
* {@link useWorkspace}). Pass `{ anchor, direction, limit, search }` to jump
|
|
34
|
+
* to a specific page or filter; omit for the newest page (default limit 100).
|
|
21
35
|
*/
|
|
22
36
|
export declare function useMembers(workspaceId: string | null, params?: MembersParams): UseQueryResult<MemberPage, StapelApiError>;
|
|
23
37
|
//# sourceMappingURL=queries.d.ts.map
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACd,MAAM,iBAAiB,CAAC;AAIzB;;;;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"}
|
package/dist/model/queries.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { useActiveSessionReady } from "@stapel/core";
|
|
2
3
|
import { useWorkspacesApi } from "./context.js";
|
|
3
4
|
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
4
5
|
/**
|
|
@@ -6,39 +7,57 @@ import { workspacesQueryKeys } from "./queryKeys.js";
|
|
|
6
7
|
* override per call site via a page that needs fresher data. Keys are
|
|
7
8
|
* namespaced (see `workspacesQueryKeys`).
|
|
8
9
|
*/
|
|
9
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* The caller's workspaces — their accepted memberships (GET /).
|
|
12
|
+
*
|
|
13
|
+
* Gated on {@link useActiveSessionReady} (owner-diagnosed live incident,
|
|
14
|
+
* 2026-07-17): unlike {@link useWorkspace}/{@link useMembers} below (both
|
|
15
|
+
* naturally disabled until a `workspaceId` is picked), this is the top-level
|
|
16
|
+
* list hook with nothing else to gate it — it fires the instant a component
|
|
17
|
+
* mounts. Without the session ready-gate this is exactly the shape of hook
|
|
18
|
+
* that raced a session still bootstrapping (e.g. right after a QR
|
|
19
|
+
* `session_share` scan set fresh cookies this JS runtime hadn't caught up
|
|
20
|
+
* to yet) and read a live session as "expired" before it had a chance to
|
|
21
|
+
* resolve — zero manual `enabled` wiring needed at each call site by design.
|
|
22
|
+
*/
|
|
10
23
|
export function useWorkspaces() {
|
|
11
24
|
const api = useWorkspacesApi();
|
|
25
|
+
const sessionReady = useActiveSessionReady();
|
|
12
26
|
return useQuery({
|
|
13
27
|
queryKey: workspacesQueryKeys.list(),
|
|
14
28
|
queryFn: () => api.listWorkspaces(),
|
|
29
|
+
enabled: sessionReady,
|
|
15
30
|
});
|
|
16
31
|
}
|
|
17
32
|
/**
|
|
18
33
|
* A single workspace by id (GET /{id}). Disabled until a `workspaceId` is
|
|
19
|
-
* given, so a detail hook can mount before a selection exists
|
|
34
|
+
* given, so a detail hook can mount before a selection exists — AND until
|
|
35
|
+
* the session is ready (a `workspaceId` can be known synchronously, e.g.
|
|
36
|
+
* from a URL param, before the session has finished bootstrapping).
|
|
20
37
|
*/
|
|
21
38
|
export function useWorkspace(workspaceId) {
|
|
22
39
|
const api = useWorkspacesApi();
|
|
40
|
+
const sessionReady = useActiveSessionReady();
|
|
23
41
|
return useQuery({
|
|
24
42
|
queryKey: workspacesQueryKeys.detail(workspaceId ?? ""),
|
|
25
43
|
queryFn: () => api.getWorkspace(workspaceId),
|
|
26
|
-
enabled: workspaceId !== null && workspaceId !== "",
|
|
44
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
27
45
|
});
|
|
28
46
|
}
|
|
29
47
|
/**
|
|
30
48
|
* A page of a workspace's members (GET /{id}/members, anchor-paginated).
|
|
31
|
-
* Disabled until a `workspaceId` is given
|
|
32
|
-
*
|
|
33
|
-
* (default limit 100).
|
|
49
|
+
* Disabled until a `workspaceId` is given (and the session is ready — see
|
|
50
|
+
* {@link useWorkspace}). Pass `{ anchor, direction, limit, search }` to jump
|
|
51
|
+
* to a specific page or filter; omit for the newest page (default limit 100).
|
|
34
52
|
*/
|
|
35
53
|
export function useMembers(workspaceId, params) {
|
|
36
54
|
const api = useWorkspacesApi();
|
|
55
|
+
const sessionReady = useActiveSessionReady();
|
|
37
56
|
const p = params ?? {};
|
|
38
57
|
return useQuery({
|
|
39
58
|
queryKey: workspacesQueryKeys.membersPage(workspaceId ?? "", p),
|
|
40
59
|
queryFn: () => api.listMembers(workspaceId, p),
|
|
41
|
-
enabled: workspaceId !== null && workspaceId !== "",
|
|
60
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
42
61
|
});
|
|
43
62
|
}
|
|
44
63
|
//# sourceMappingURL=queries.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAQrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,qBAAqB,EAAE,CAAC;IAC7C,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,mBAAmB,CAAC,IAAI,EAAE;QACpC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,cAAc,EAAE;QACnC,OAAO,EAAE,YAAY;KACtB,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,WAA0B;IAE1B,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,qBAAqB,EAAE,CAAC;IAC7C,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,YAAY,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,EAAE;KACpE,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACxB,WAA0B,EAC1B,MAAsB;IAEtB,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,qBAAqB,EAAE,CAAC;IAC7C,MAAM,CAAC,GAAG,MAAM,IAAI,EAAE,CAAC;IACvB,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,mBAAmB,CAAC,WAAW,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,CAAC;QAC/D,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,WAAqB,EAAE,CAAC,CAAC;QACxD,OAAO,EAAE,YAAY,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,KAAK,EAAE;KACpE,CAAC,CAAC;AACL,CAAC"}
|
package/llms.txt
CHANGED
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stapel/workspaces-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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,9 +82,9 @@
|
|
|
82
82
|
"size-limit": "^11.2.0",
|
|
83
83
|
"typescript": "^5.8.3",
|
|
84
84
|
"vitest": "^3.2.4",
|
|
85
|
-
"@stapel/core": "^0.
|
|
86
|
-
"@stapel/
|
|
87
|
-
"@stapel/
|
|
85
|
+
"@stapel/core": "^0.6.0",
|
|
86
|
+
"@stapel/tokens": "^0.4.0",
|
|
87
|
+
"@stapel/showcase": "^0.2.0"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
90
90
|
"node": ">=22"
|
package/src/model/queries.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
2
|
import type { UseQueryResult } from "@tanstack/react-query";
|
|
3
|
+
import { useActiveSessionReady } from "@stapel/core";
|
|
3
4
|
import type { StapelApiError } from "@stapel/core";
|
|
4
5
|
import type {
|
|
5
6
|
MemberPage,
|
|
@@ -16,45 +17,63 @@ import { workspacesQueryKeys } from "./queryKeys.js";
|
|
|
16
17
|
* namespaced (see `workspacesQueryKeys`).
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* The caller's workspaces — their accepted memberships (GET /).
|
|
22
|
+
*
|
|
23
|
+
* Gated on {@link useActiveSessionReady} (owner-diagnosed live incident,
|
|
24
|
+
* 2026-07-17): unlike {@link useWorkspace}/{@link useMembers} below (both
|
|
25
|
+
* naturally disabled until a `workspaceId` is picked), this is the top-level
|
|
26
|
+
* list hook with nothing else to gate it — it fires the instant a component
|
|
27
|
+
* mounts. Without the session ready-gate this is exactly the shape of hook
|
|
28
|
+
* that raced a session still bootstrapping (e.g. right after a QR
|
|
29
|
+
* `session_share` scan set fresh cookies this JS runtime hadn't caught up
|
|
30
|
+
* to yet) and read a live session as "expired" before it had a chance to
|
|
31
|
+
* resolve — zero manual `enabled` wiring needed at each call site by design.
|
|
32
|
+
*/
|
|
20
33
|
export function useWorkspaces(): UseQueryResult<WorkspaceList, StapelApiError> {
|
|
21
34
|
const api = useWorkspacesApi();
|
|
35
|
+
const sessionReady = useActiveSessionReady();
|
|
22
36
|
return useQuery({
|
|
23
37
|
queryKey: workspacesQueryKeys.list(),
|
|
24
38
|
queryFn: () => api.listWorkspaces(),
|
|
39
|
+
enabled: sessionReady,
|
|
25
40
|
});
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
/**
|
|
29
44
|
* A single workspace by id (GET /{id}). Disabled until a `workspaceId` is
|
|
30
|
-
* given, so a detail hook can mount before a selection exists
|
|
45
|
+
* given, so a detail hook can mount before a selection exists — AND until
|
|
46
|
+
* the session is ready (a `workspaceId` can be known synchronously, e.g.
|
|
47
|
+
* from a URL param, before the session has finished bootstrapping).
|
|
31
48
|
*/
|
|
32
49
|
export function useWorkspace(
|
|
33
50
|
workspaceId: string | null
|
|
34
51
|
): UseQueryResult<Workspace, StapelApiError> {
|
|
35
52
|
const api = useWorkspacesApi();
|
|
53
|
+
const sessionReady = useActiveSessionReady();
|
|
36
54
|
return useQuery({
|
|
37
55
|
queryKey: workspacesQueryKeys.detail(workspaceId ?? ""),
|
|
38
56
|
queryFn: () => api.getWorkspace(workspaceId as string),
|
|
39
|
-
enabled: workspaceId !== null && workspaceId !== "",
|
|
57
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
40
58
|
});
|
|
41
59
|
}
|
|
42
60
|
|
|
43
61
|
/**
|
|
44
62
|
* A page of a workspace's members (GET /{id}/members, anchor-paginated).
|
|
45
|
-
* Disabled until a `workspaceId` is given
|
|
46
|
-
*
|
|
47
|
-
* (default limit 100).
|
|
63
|
+
* Disabled until a `workspaceId` is given (and the session is ready — see
|
|
64
|
+
* {@link useWorkspace}). Pass `{ anchor, direction, limit, search }` to jump
|
|
65
|
+
* to a specific page or filter; omit for the newest page (default limit 100).
|
|
48
66
|
*/
|
|
49
67
|
export function useMembers(
|
|
50
68
|
workspaceId: string | null,
|
|
51
69
|
params?: MembersParams
|
|
52
70
|
): UseQueryResult<MemberPage, StapelApiError> {
|
|
53
71
|
const api = useWorkspacesApi();
|
|
72
|
+
const sessionReady = useActiveSessionReady();
|
|
54
73
|
const p = params ?? {};
|
|
55
74
|
return useQuery({
|
|
56
75
|
queryKey: workspacesQueryKeys.membersPage(workspaceId ?? "", p),
|
|
57
76
|
queryFn: () => api.listMembers(workspaceId as string, p),
|
|
58
|
-
enabled: workspaceId !== null && workspaceId !== "",
|
|
77
|
+
enabled: sessionReady && workspaceId !== null && workspaceId !== "",
|
|
59
78
|
});
|
|
60
79
|
}
|