@stapel/workspaces-react 0.1.0 → 0.4.1
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 +90 -0
- package/README.md +45 -3
- package/dist/api/generated/schema.d.ts +759 -0
- package/dist/api/generated/schema.d.ts.map +1 -0
- package/dist/api/generated/schema.js +2 -0
- package/dist/api/generated/schema.js.map +1 -0
- package/dist/api/types.d.ts +22 -6
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/workspacesApi.d.ts +3 -3
- package/dist/api/workspacesApi.d.ts.map +1 -1
- package/dist/api/workspacesApi.js +14 -1
- package/dist/api/workspacesApi.js.map +1 -1
- package/dist/flows/registry.d.ts +22 -0
- package/dist/flows/registry.d.ts.map +1 -0
- package/dist/flows/registry.js +20 -0
- package/dist/flows/registry.js.map +1 -0
- package/dist/headless/Members.d.ts +6 -1
- package/dist/headless/Members.d.ts.map +1 -1
- package/dist/headless/Members.js +1 -1
- package/dist/headless/Members.js.map +1 -1
- package/dist/headless/WorkspacesProvider.d.ts +5 -4
- package/dist/headless/WorkspacesProvider.d.ts.map +1 -1
- package/dist/headless/WorkspacesProvider.js +5 -7
- package/dist/headless/WorkspacesProvider.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/model/context.d.ts +6 -9
- package/dist/model/context.d.ts.map +1 -1
- package/dist/model/context.js +11 -16
- package/dist/model/context.js.map +1 -1
- package/dist/model/queries.d.ts +6 -4
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +8 -5
- package/dist/model/queries.js.map +1 -1
- package/dist/model/queryKeys.d.ts +2 -0
- package/dist/model/queryKeys.d.ts.map +1 -1
- package/dist/model/queryKeys.js +3 -0
- package/dist/model/queryKeys.js.map +1 -1
- package/dist/model/runtime.d.ts +12 -21
- package/dist/model/runtime.d.ts.map +1 -1
- package/dist/model/runtime.js +2 -14
- package/dist/model/runtime.js.map +1 -1
- package/llms.txt +14 -14
- package/manifest.json +34 -32
- package/package.json +5 -4
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +761 -0
- package/src/api/types.ts +23 -6
- package/src/api/workspacesApi.ts +17 -5
- package/src/flows/registry.ts +32 -0
- package/src/headless/Members.tsx +7 -2
- package/src/headless/WorkspacesProvider.tsx +6 -11
- package/src/index.ts +4 -3
- package/src/model/context.tsx +16 -17
- package/src/model/queries.ts +16 -7
- package/src/model/queryKeys.ts +9 -0
- package/src/model/runtime.ts +14 -35
- package/dist/flows/generated/flows.gen.d.ts +0 -19
- package/dist/flows/generated/flows.gen.d.ts.map +0 -1
- package/dist/flows/generated/flows.gen.js +0 -23
- package/dist/flows/generated/flows.gen.js.map +0 -1
- package/src/flows/generated/flows.gen.ts +0 -38
- package/src/flows/generated/flows.json +0 -1
package/src/api/types.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Wire types for the stapel-workspaces HTTP contract — **derived from the generated
|
|
3
3
|
* OpenAPI surface** (frontend-standard §2/§3), never hand-maintained. The
|
|
4
|
-
* single source of truth is `components["schemas"]` from
|
|
5
|
-
* (
|
|
6
|
-
*
|
|
4
|
+
* single source of truth is `components["schemas"]` from this pair's own
|
|
5
|
+
* package-LOCAL generated schema (`./generated/schema.js`, produced by
|
|
6
|
+
* `pnpm gen:api` from stapel-workspaces's OWN `docs/schema.json` — the
|
|
7
|
+
* §17-native per-module contract, not the unified monolith). Alias the schemas this pair uses under local
|
|
7
8
|
* names here; do NOT write parallel response bodies. Where drf-spectacular +
|
|
8
9
|
* openapi-typescript under-describe the runtime, apply a small documented
|
|
9
10
|
* correction (see auth-react `api/types.ts` for the three canonical patterns).
|
|
10
11
|
*/
|
|
11
|
-
import type { components } from "
|
|
12
|
+
import type { components } from "./generated/schema.js";
|
|
12
13
|
|
|
13
14
|
/** The generated schema table — the one source of truth for wire shapes. */
|
|
14
15
|
export type Schemas = components["schemas"];
|
|
@@ -25,8 +26,8 @@ export type WorkspaceCreate = Schemas["WorkspaceCreateRequest"];
|
|
|
25
26
|
export type WorkspaceUpdate = Schemas["PatchedWorkspaceUpdateRequest"];
|
|
26
27
|
/** One workspace member (GET members, PATCH member role, POST accept). */
|
|
27
28
|
export type Member = Schemas["MemberResponse"];
|
|
28
|
-
/** GET /{id}/members 200 body — a workspace's
|
|
29
|
-
export type
|
|
29
|
+
/** GET /{id}/members 200 body — an anchor-paginated page of a workspace's {@link Member}s. */
|
|
30
|
+
export type MemberPage = Schemas["PaginatedMemberResponseList"];
|
|
30
31
|
/** POST /{id}/members/invite request body — one or more emails + a role. */
|
|
31
32
|
export type MemberInvite = Schemas["MemberInviteRequest"];
|
|
32
33
|
/** POST /{id}/members/invite 201 body — the created invitations. */
|
|
@@ -56,3 +57,19 @@ export type WorkspaceRole = "owner" | "admin" | "member" | "viewer";
|
|
|
56
57
|
* {@link WorkspaceRole}.
|
|
57
58
|
*/
|
|
58
59
|
export type WorkspaceKind = "personal" | "work";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Anchor-pagination query for GET /{id}/members (core `AnchorPagination`, same
|
|
63
|
+
* shape as notifications-react's `NotificationFeedParams`). All optional: no
|
|
64
|
+
* params fetches the newest page (default limit 100, max 500).
|
|
65
|
+
*/
|
|
66
|
+
export interface MembersParams {
|
|
67
|
+
/** Anchor value to paginate from (exclusive) — a page's `next_anchor`. */
|
|
68
|
+
readonly anchor?: string;
|
|
69
|
+
/** Pagination direction relative to `anchor`. */
|
|
70
|
+
readonly direction?: "next" | "prev" | "center";
|
|
71
|
+
/** Page size (default 100, max 500). */
|
|
72
|
+
readonly limit?: number;
|
|
73
|
+
/** Case-insensitive substring filter matched against a member's email or display name. */
|
|
74
|
+
readonly search?: string;
|
|
75
|
+
}
|
package/src/api/workspacesApi.ts
CHANGED
|
@@ -3,8 +3,9 @@ import type {
|
|
|
3
3
|
Member,
|
|
4
4
|
MemberInvite,
|
|
5
5
|
MemberInviteResult,
|
|
6
|
-
|
|
6
|
+
MemberPage,
|
|
7
7
|
MemberRoleUpdate,
|
|
8
|
+
MembersParams,
|
|
8
9
|
InvitationAccept,
|
|
9
10
|
Workspace,
|
|
10
11
|
WorkspaceCreate,
|
|
@@ -64,8 +65,11 @@ export interface WorkspacesApi {
|
|
|
64
65
|
/** Soft-delete a workspace (owner only). */
|
|
65
66
|
deleteWorkspace(workspaceId: string): Promise<void>;
|
|
66
67
|
|
|
67
|
-
/** A workspace's members (viewer+). */
|
|
68
|
-
listMembers(
|
|
68
|
+
/** A workspace's members (viewer+), an anchor-paginated page. */
|
|
69
|
+
listMembers(
|
|
70
|
+
workspaceId: string,
|
|
71
|
+
params?: MembersParams
|
|
72
|
+
): Promise<MemberPage>;
|
|
69
73
|
/** Invite one or more emails to a workspace at a role (admin+). */
|
|
70
74
|
inviteMembers(
|
|
71
75
|
workspaceId: string,
|
|
@@ -106,8 +110,16 @@ export function createWorkspacesApi(client: StapelClient): WorkspacesApi {
|
|
|
106
110
|
deleteWorkspace: (workspaceId) =>
|
|
107
111
|
client.delete(`/${encodeURIComponent(workspaceId)}`, mutating()),
|
|
108
112
|
|
|
109
|
-
listMembers: (workspaceId) =>
|
|
110
|
-
|
|
113
|
+
listMembers: (workspaceId, params) => {
|
|
114
|
+
const query: Record<string, string | number> = {};
|
|
115
|
+
if (params?.anchor !== undefined) query.anchor = params.anchor;
|
|
116
|
+
if (params?.direction !== undefined) query.direction = params.direction;
|
|
117
|
+
if (params?.limit !== undefined) query.limit = params.limit;
|
|
118
|
+
if (params?.search !== undefined) query.search = params.search;
|
|
119
|
+
return client.get(`/${encodeURIComponent(workspaceId)}/members`, {
|
|
120
|
+
query,
|
|
121
|
+
});
|
|
122
|
+
},
|
|
111
123
|
|
|
112
124
|
inviteMembers: (workspaceId, body) =>
|
|
113
125
|
client.post(
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-flow registry shim (slim wave §21/S3). stapel-workspaces annotates no
|
|
3
|
+
* `@flow_step` yet — its backend `docs/flows.json` carries no `workspaces.*`
|
|
4
|
+
* flows, so `gen:flows` skips emission for this pair (no `flows/generated/`
|
|
5
|
+
* scaffolding). This hand-written shim preserves the pair's public
|
|
6
|
+
* flow-registry surface at its zero-flow shape.
|
|
7
|
+
*
|
|
8
|
+
* When the backend annotates flows, `pnpm gen:flows` emits
|
|
9
|
+
* `./generated/flows.gen.ts` again — replace these exports with re-exports
|
|
10
|
+
* from it (the shapes match by construction) and delete this file.
|
|
11
|
+
*/
|
|
12
|
+
export const WORKSPACES_FLOWS = {} as const;
|
|
13
|
+
|
|
14
|
+
/** Canonical flow ids present in flows.json (none yet — see above). */
|
|
15
|
+
export type WorkspacesFlowId = keyof typeof WORKSPACES_FLOWS;
|
|
16
|
+
|
|
17
|
+
export type WorkspacesFlowSpec = (typeof WORKSPACES_FLOWS)[WorkspacesFlowId];
|
|
18
|
+
|
|
19
|
+
export interface FlowEndpoint {
|
|
20
|
+
readonly method: string;
|
|
21
|
+
readonly path: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
25
|
+
export function flowEndpoints(id: WorkspacesFlowId): readonly FlowEndpoint[] {
|
|
26
|
+
// Same widened body as the generated registry's — valid for the zero-flow
|
|
27
|
+
// shape AND correct once flows exist.
|
|
28
|
+
const spec = WORKSPACES_FLOWS[id] as
|
|
29
|
+
| { readonly steps: readonly { readonly endpoints: readonly FlowEndpoint[] }[] }
|
|
30
|
+
| undefined;
|
|
31
|
+
return spec ? spec.steps.flatMap((s) => s.endpoints) : [];
|
|
32
|
+
}
|
package/src/headless/Members.tsx
CHANGED
|
@@ -11,7 +11,12 @@ import type { MemberRoleChange } from "../model/mutations.js";
|
|
|
11
11
|
|
|
12
12
|
/** Render-prop bag for {@link Members}. */
|
|
13
13
|
export interface MembersBag {
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* The workspace's members once loaded (empty before load). This is one page
|
|
16
|
+
* (default 100) — the roster's own {@link Member.email}/`search` narrows
|
|
17
|
+
* further; a full pager is out of scope for this renderless view (bring
|
|
18
|
+
* your own via `useMembers`' `params` for anchor pagination).
|
|
19
|
+
*/
|
|
15
20
|
readonly members: readonly Member[];
|
|
16
21
|
/** The initial member-list load is in flight. */
|
|
17
22
|
readonly isLoading: boolean;
|
|
@@ -57,7 +62,7 @@ export function Members(props: {
|
|
|
57
62
|
const roleMutation = useUpdateMemberRole(props.workspaceId);
|
|
58
63
|
const removeMutation = useRemoveMember(props.workspaceId);
|
|
59
64
|
return props.children({
|
|
60
|
-
members: query.data?.
|
|
65
|
+
members: query.data?.items ?? [],
|
|
61
66
|
isLoading: query.isLoading,
|
|
62
67
|
isError:
|
|
63
68
|
query.isError ||
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { ModuleProvider } from "../model/context.js";
|
|
3
3
|
import type { WorkspacesRuntime } from "../model/runtime.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Provides the wired {@link WorkspacesRuntime} to every workspaces hook and
|
|
7
7
|
* headless component below it. Bring your own visual shell — this component
|
|
8
|
-
* renders nothing of its own.
|
|
8
|
+
* renders nothing of its own. (Core's `createModuleContext` provider, bound
|
|
9
|
+
* to this pair — slim wave §21/S2.)
|
|
9
10
|
*
|
|
10
11
|
* ```tsx
|
|
11
|
-
* const runtime = createWorkspacesRuntime({ baseUrl: "/workspaces/api/" });
|
|
12
|
+
* const runtime = createWorkspacesRuntime({ baseUrl: "/workspaces/api/v1/" });
|
|
12
13
|
* // give runtime.client to core's <StapelConfigProvider config={{ client }}>
|
|
13
14
|
* <WorkspacesProvider runtime={runtime}>{app}</WorkspacesProvider>
|
|
14
15
|
* ```
|
|
15
16
|
*/
|
|
16
|
-
export
|
|
17
|
+
export const WorkspacesProvider: (props: {
|
|
17
18
|
runtime: WorkspacesRuntime;
|
|
18
19
|
children: ReactNode;
|
|
19
|
-
})
|
|
20
|
-
return (
|
|
21
|
-
<WorkspacesRuntimeContext.Provider value={props.runtime}>
|
|
22
|
-
{props.children}
|
|
23
|
-
</WorkspacesRuntimeContext.Provider>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
20
|
+
}) => ReactElement = ModuleProvider;
|
package/src/index.ts
CHANGED
|
@@ -25,12 +25,12 @@ export type {
|
|
|
25
25
|
FlowError,
|
|
26
26
|
} from "@stapel/core";
|
|
27
27
|
export { toFlowError } from "./flows/errors.js";
|
|
28
|
-
export { WORKSPACES_FLOWS, flowEndpoints } from "./flows/
|
|
28
|
+
export { WORKSPACES_FLOWS, flowEndpoints } from "./flows/registry.js";
|
|
29
29
|
export type {
|
|
30
30
|
WorkspacesFlowId,
|
|
31
31
|
WorkspacesFlowSpec,
|
|
32
32
|
FlowEndpoint,
|
|
33
|
-
} from "./flows/
|
|
33
|
+
} from "./flows/registry.js";
|
|
34
34
|
|
|
35
35
|
// ── model (runtime wiring, query keys, context) ──────────────────────────────
|
|
36
36
|
export { createWorkspacesRuntime } from "./model/runtime.js";
|
|
@@ -72,7 +72,8 @@ export type {
|
|
|
72
72
|
WorkspaceCreate,
|
|
73
73
|
WorkspaceUpdate,
|
|
74
74
|
Member as MemberData,
|
|
75
|
-
|
|
75
|
+
MemberPage as MemberListData,
|
|
76
|
+
MembersParams,
|
|
76
77
|
MemberInvite,
|
|
77
78
|
MemberInviteResult,
|
|
78
79
|
MemberRoleUpdate,
|
package/src/model/context.tsx
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
2
1
|
import type { Context } from "react";
|
|
3
|
-
import
|
|
2
|
+
import { createModuleContext } from "@stapel/core";
|
|
3
|
+
import type { Analytics, ModuleContextKit } from "@stapel/core";
|
|
4
4
|
import type { WorkspacesApi } from "../api/workspacesApi.js";
|
|
5
5
|
import type { WorkspacesRuntime } from "./runtime.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* The wired WorkspacesRuntime shared through React context by
|
|
9
9
|
* `<WorkspacesProvider>`. Hooks in `model/` and `headless/` read the singletons
|
|
10
|
-
* from here.
|
|
10
|
+
* from here. One reviewed copy of this plumbing lives in `@stapel/core`
|
|
11
|
+
* (`createModuleContext`, slim wave §21/S2); this module binds it under the
|
|
12
|
+
* pair's public names.
|
|
11
13
|
*/
|
|
14
|
+
const kit: ModuleContextKit<WorkspacesRuntime> =
|
|
15
|
+
createModuleContext<WorkspacesRuntime>("Workspaces");
|
|
16
|
+
|
|
12
17
|
export const WorkspacesRuntimeContext: Context<WorkspacesRuntime | null> =
|
|
13
|
-
|
|
18
|
+
kit.RuntimeContext;
|
|
19
|
+
|
|
20
|
+
export const useWorkspacesRuntime: () => WorkspacesRuntime = kit.useRuntime;
|
|
14
21
|
|
|
15
|
-
export
|
|
16
|
-
const runtime = useContext(WorkspacesRuntimeContext);
|
|
17
|
-
if (runtime === null) {
|
|
18
|
-
throw new Error("Workspaces hooks must be used within a <WorkspacesProvider>");
|
|
19
|
-
}
|
|
20
|
-
return runtime;
|
|
21
|
-
}
|
|
22
|
+
export const useWorkspacesApi: () => WorkspacesApi = kit.useApi;
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
return useWorkspacesRuntime().api;
|
|
25
|
-
}
|
|
24
|
+
export const useWorkspacesAnalytics: () => Analytics | null = kit.useAnalytics;
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
/** @internal Re-exported as `<WorkspacesProvider>` from `headless/`. */
|
|
27
|
+
export const ModuleProvider: ModuleContextKit<WorkspacesRuntime>["Provider"] =
|
|
28
|
+
kit.Provider;
|
package/src/model/queries.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
2
|
import type { UseQueryResult } from "@tanstack/react-query";
|
|
3
3
|
import type { StapelApiError } from "@stapel/core";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
MemberPage,
|
|
6
|
+
MembersParams,
|
|
7
|
+
Workspace,
|
|
8
|
+
WorkspaceList,
|
|
9
|
+
} from "../api/types.js";
|
|
5
10
|
import { useWorkspacesApi } from "./context.js";
|
|
6
11
|
import { workspacesQueryKeys } from "./queryKeys.js";
|
|
7
12
|
|
|
@@ -36,16 +41,20 @@ export function useWorkspace(
|
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
/**
|
|
39
|
-
* A workspace's members (GET /{id}/members).
|
|
40
|
-
* given.
|
|
44
|
+
* A page of a workspace's members (GET /{id}/members, anchor-paginated).
|
|
45
|
+
* Disabled until a `workspaceId` is given. Pass `{ anchor, direction, limit,
|
|
46
|
+
* search }` to jump to a specific page or filter; omit for the newest page
|
|
47
|
+
* (default limit 100).
|
|
41
48
|
*/
|
|
42
49
|
export function useMembers(
|
|
43
|
-
workspaceId: string | null
|
|
44
|
-
|
|
50
|
+
workspaceId: string | null,
|
|
51
|
+
params?: MembersParams
|
|
52
|
+
): UseQueryResult<MemberPage, StapelApiError> {
|
|
45
53
|
const api = useWorkspacesApi();
|
|
54
|
+
const p = params ?? {};
|
|
46
55
|
return useQuery({
|
|
47
|
-
queryKey: workspacesQueryKeys.
|
|
48
|
-
queryFn: () => api.listMembers(workspaceId as string),
|
|
56
|
+
queryKey: workspacesQueryKeys.membersPage(workspaceId ?? "", p),
|
|
57
|
+
queryFn: () => api.listMembers(workspaceId as string, p),
|
|
49
58
|
enabled: workspaceId !== null && workspaceId !== "",
|
|
50
59
|
});
|
|
51
60
|
}
|
package/src/model/queryKeys.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { MembersParams } from "../api/types.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Namespaced TanStack Query keys (frontend-standard §2 — "ключи неймспейснуты").
|
|
3
5
|
* Everything under the `"workspaces"` root so a host can invalidate the whole
|
|
@@ -12,9 +14,16 @@ export const workspacesQueryKeys: {
|
|
|
12
14
|
list(): readonly ["workspaces", "list"];
|
|
13
15
|
detail(workspaceId: string): readonly ["workspaces", "detail", string];
|
|
14
16
|
members(workspaceId: string): readonly ["workspaces", "members", string];
|
|
17
|
+
membersPage(
|
|
18
|
+
workspaceId: string,
|
|
19
|
+
params: MembersParams
|
|
20
|
+
): readonly ["workspaces", "members", string, MembersParams];
|
|
15
21
|
} = {
|
|
16
22
|
all: [ROOT],
|
|
17
23
|
list: () => [ROOT, "list"],
|
|
18
24
|
detail: (workspaceId) => [ROOT, "detail", workspaceId],
|
|
25
|
+
// The bare 3-tuple is a valid prefix of membersPage's 4-tuple, so
|
|
26
|
+
// invalidating `members(workspaceId)` (mutations.ts) drops every page.
|
|
19
27
|
members: (workspaceId) => [ROOT, "members", workspaceId],
|
|
28
|
+
membersPage: (workspaceId, params) => [ROOT, "members", workspaceId, params],
|
|
20
29
|
};
|
package/src/model/runtime.ts
CHANGED
|
@@ -1,46 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
1
|
+
import { createModuleRuntime } from "@stapel/core";
|
|
2
|
+
import type { CreateModuleRuntimeOptions, ModuleRuntime } from "@stapel/core";
|
|
3
3
|
import { createWorkspacesApi } from "../api/workspacesApi.js";
|
|
4
4
|
import type { WorkspacesApi } from "../api/workspacesApi.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* The wired workspaces runtime —
|
|
8
|
-
* API
|
|
9
|
-
* `
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* The wired workspaces runtime — core's `ModuleRuntime` bound to this pair's
|
|
8
|
+
* API (slim wave §21/S2: the plumbing lives once in `@stapel/core`'s
|
|
9
|
+
* `createModuleRuntime`/`createModuleContext`; this module only binds the
|
|
10
|
+
* module-prefixed names). The returned `client` is what the host injects
|
|
11
|
+
* into core's `StapelConfigProvider` (as the default or the `"workspaces"`
|
|
12
|
+
* module client), preserving the client-injection fork seam
|
|
13
|
+
* (frontend-standard §7.2). Auth token/refresh and the verification-403 seam
|
|
14
|
+
* are supplied by the host's auth runtime on the shared client — this pair
|
|
15
|
+
* does not re-implement them.
|
|
13
16
|
*/
|
|
14
|
-
export
|
|
15
|
-
readonly client: StapelClient;
|
|
16
|
-
readonly api: WorkspacesApi;
|
|
17
|
-
readonly analytics: Analytics | null;
|
|
18
|
-
}
|
|
17
|
+
export type WorkspacesRuntime = ModuleRuntime<WorkspacesApi>;
|
|
19
18
|
|
|
20
|
-
export
|
|
21
|
-
/** e.g. `/workspaces/api/` or `https://app.example.com/workspaces/api/`. */
|
|
22
|
-
readonly baseUrl: string;
|
|
23
|
-
readonly fetch?: typeof globalThis.fetch;
|
|
24
|
-
readonly credentials?: RequestCredentials;
|
|
25
|
-
readonly analytics?: Analytics | null;
|
|
26
|
-
/** Extra headers merged into every request (e.g. a tenant id). */
|
|
27
|
-
readonly defaultHeaders?: Record<string, string>;
|
|
28
|
-
}
|
|
19
|
+
export type CreateWorkspacesRuntimeOptions = CreateModuleRuntimeOptions;
|
|
29
20
|
|
|
30
21
|
export function createWorkspacesRuntime(
|
|
31
22
|
options: CreateWorkspacesRuntimeOptions
|
|
32
23
|
): WorkspacesRuntime {
|
|
33
|
-
|
|
34
|
-
const client = createStapelClient({
|
|
35
|
-
baseUrl: options.baseUrl,
|
|
36
|
-
...(options.fetch !== undefined ? { fetch: options.fetch } : {}),
|
|
37
|
-
...(options.credentials !== undefined
|
|
38
|
-
? { credentials: options.credentials }
|
|
39
|
-
: {}),
|
|
40
|
-
...(options.defaultHeaders !== undefined
|
|
41
|
-
? { defaultHeaders: options.defaultHeaders }
|
|
42
|
-
: {}),
|
|
43
|
-
});
|
|
44
|
-
const api = createWorkspacesApi(client);
|
|
45
|
-
return { client, api, analytics };
|
|
24
|
+
return createModuleRuntime(createWorkspacesApi, options);
|
|
46
25
|
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The canonical workspaces flow registry — the machine-facing projection of the
|
|
3
|
-
* flow source (docs/flow-system.md §5). Each entry carries a flow's canonical
|
|
4
|
-
* id (`flow.<id>.<step>` analytics funnel = this flow), its i18n keys, and its
|
|
5
|
-
* ordered step→endpoint contract. Flow machines bind their `id` to
|
|
6
|
-
* `WORKSPACES_FLOWS[...].id` so a backend flow rename/re-step surfaces as a drift
|
|
7
|
-
* here (`pnpm gen:flows:check`) rather than a silent analytics/contract skew.
|
|
8
|
-
*/
|
|
9
|
-
export declare const WORKSPACES_FLOWS: {};
|
|
10
|
-
/** Canonical flow ids present in flows.json (a subset grows as the backend annotates more). */
|
|
11
|
-
export type WorkspacesFlowId = keyof typeof WORKSPACES_FLOWS;
|
|
12
|
-
export type WorkspacesFlowSpec = (typeof WORKSPACES_FLOWS)[WorkspacesFlowId];
|
|
13
|
-
export interface FlowEndpoint {
|
|
14
|
-
readonly method: string;
|
|
15
|
-
readonly path: string;
|
|
16
|
-
}
|
|
17
|
-
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
18
|
-
export declare function flowEndpoints(id: WorkspacesFlowId): readonly FlowEndpoint[];
|
|
19
|
-
//# sourceMappingURL=flows.gen.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flows.gen.d.ts","sourceRoot":"","sources":["../../../src/flows/generated/flows.gen.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,IAEnB,CAAC;AAEX,+FAA+F;AAC/F,MAAM,MAAM,gBAAgB,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,gBAAgB,CAAC,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,EAAE,EAAE,gBAAgB,GAAG,SAAS,YAAY,EAAE,CAU3E"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/gen-flows.mjs — do not edit by hand.
|
|
2
|
-
// Source: unified Stapel flows.json (stapel-example-monolith `make codegen`).
|
|
3
|
-
// Regenerate: pnpm gen:flows · Drift gate: pnpm gen:flows:check
|
|
4
|
-
/**
|
|
5
|
-
* The canonical workspaces flow registry — the machine-facing projection of the
|
|
6
|
-
* flow source (docs/flow-system.md §5). Each entry carries a flow's canonical
|
|
7
|
-
* id (`flow.<id>.<step>` analytics funnel = this flow), its i18n keys, and its
|
|
8
|
-
* ordered step→endpoint contract. Flow machines bind their `id` to
|
|
9
|
-
* `WORKSPACES_FLOWS[...].id` so a backend flow rename/re-step surfaces as a drift
|
|
10
|
-
* here (`pnpm gen:flows:check`) rather than a silent analytics/contract skew.
|
|
11
|
-
*/
|
|
12
|
-
export const WORKSPACES_FLOWS = {};
|
|
13
|
-
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
14
|
-
export function flowEndpoints(id) {
|
|
15
|
-
// Guard the empty-registry case: a module with no annotated flows makes
|
|
16
|
-
// `WorkspacesFlowId` = `never` and `WORKSPACES_FLOWS` = `{}`, so a direct
|
|
17
|
-
// `WORKSPACES_FLOWS[id].steps` does not type-check. Widening to an optional spec
|
|
18
|
-
// keeps this body valid for the zero-flow scaffold AND correct once the
|
|
19
|
-
// backend annotates `@flow_step` and the registry fills in.
|
|
20
|
-
const spec = WORKSPACES_FLOWS[id];
|
|
21
|
-
return spec ? spec.steps.flatMap((s) => s.endpoints) : [];
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=flows.gen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flows.gen.js","sourceRoot":"","sources":["../../../src/flows/generated/flows.gen.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,8EAA8E;AAC9E,oEAAoE;AAEpE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAEtB,CAAC;AAYX,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAAC,EAAoB;IAChD,wEAAwE;IACxE,0EAA0E;IAC1E,iFAAiF;IACjF,wEAAwE;IACxE,4DAA4D;IAC5D,MAAM,IAAI,GAAG,gBAAgB,CAAC,EAAE,CAEnB,CAAC;IACd,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/gen-flows.mjs — do not edit by hand.
|
|
2
|
-
// Source: unified Stapel flows.json (stapel-example-monolith `make codegen`).
|
|
3
|
-
// Regenerate: pnpm gen:flows · Drift gate: pnpm gen:flows:check
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* The canonical workspaces flow registry — the machine-facing projection of the
|
|
7
|
-
* flow source (docs/flow-system.md §5). Each entry carries a flow's canonical
|
|
8
|
-
* id (`flow.<id>.<step>` analytics funnel = this flow), its i18n keys, and its
|
|
9
|
-
* ordered step→endpoint contract. Flow machines bind their `id` to
|
|
10
|
-
* `WORKSPACES_FLOWS[...].id` so a backend flow rename/re-step surfaces as a drift
|
|
11
|
-
* here (`pnpm gen:flows:check`) rather than a silent analytics/contract skew.
|
|
12
|
-
*/
|
|
13
|
-
export const WORKSPACES_FLOWS = {
|
|
14
|
-
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
/** Canonical flow ids present in flows.json (a subset grows as the backend annotates more). */
|
|
18
|
-
export type WorkspacesFlowId = keyof typeof WORKSPACES_FLOWS;
|
|
19
|
-
|
|
20
|
-
export type WorkspacesFlowSpec = (typeof WORKSPACES_FLOWS)[WorkspacesFlowId];
|
|
21
|
-
|
|
22
|
-
export interface FlowEndpoint {
|
|
23
|
-
readonly method: string;
|
|
24
|
-
readonly path: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** All HTTP endpoints a flow touches, in step order (for the contract test / MSW). */
|
|
28
|
-
export function flowEndpoints(id: WorkspacesFlowId): readonly FlowEndpoint[] {
|
|
29
|
-
// Guard the empty-registry case: a module with no annotated flows makes
|
|
30
|
-
// `WorkspacesFlowId` = `never` and `WORKSPACES_FLOWS` = `{}`, so a direct
|
|
31
|
-
// `WORKSPACES_FLOWS[id].steps` does not type-check. Widening to an optional spec
|
|
32
|
-
// keeps this body valid for the zero-flow scaffold AND correct once the
|
|
33
|
-
// backend annotates `@flow_step` and the registry fills in.
|
|
34
|
-
const spec = WORKSPACES_FLOWS[id] as
|
|
35
|
-
| { readonly steps: readonly { readonly endpoints: readonly FlowEndpoint[] }[] }
|
|
36
|
-
| undefined;
|
|
37
|
-
return spec ? spec.steps.flatMap((s) => s.endpoints) : [];
|
|
38
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[]
|