@ploykit/ui 0.2.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/README.md +201 -41
- package/dist/AppProviders.d.ts +15 -0
- package/dist/AppProviders.js +15 -0
- package/dist/components/ConfirmDialog.js +8 -2
- package/dist/components/DataTable.d.ts +12 -3
- package/dist/components/DataTable.js +6 -2
- package/dist/components/ErrorBoundary.js +1 -1
- package/dist/components/NotificationBell.js +4 -4
- package/dist/components/ReauthDialog.d.ts +15 -0
- package/dist/components/ReauthDialog.js +42 -0
- package/dist/components/SecretModal.d.ts +8 -1
- package/dist/components/SecretModal.js +5 -2
- package/dist/components/ui/{Badge.d.ts → badge.d.ts} +1 -1
- package/dist/components/ui/{Button.d.ts → button.d.ts} +1 -1
- package/dist/components/ui/dialog.d.ts +7 -1
- package/dist/components/ui/dialog.js +7 -2
- package/dist/components/ui/select.d.ts +20 -1
- package/dist/components/ui/select.js +22 -1
- package/dist/components/ui/sheet.d.ts +9 -1
- package/dist/components/ui/sheet.js +9 -2
- package/dist/components/ui/textarea.d.ts +9 -0
- package/dist/components/ui/textarea.js +12 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/pages/LandingPage.js +1 -1
- package/dist/pages/LoginPage.js +2 -2
- package/dist/pages/account/ProfileSettingsPage.js +1 -1
- package/dist/pages/account/SecuritySettingsPage.js +1 -1
- package/dist/pages/auth/InviteAcceptPage.js +1 -1
- package/dist/pages/auth/ResetPasswordPage.js +1 -1
- package/dist/pages/auth/VerifyEmailPage.js +1 -1
- package/dist/pages/workspace/RolePermissionsPage.d.ts +3 -0
- package/dist/pages/workspace/RolePermissionsPage.js +118 -0
- package/package.json +3 -3
- package/dist/components/ui/menu.d.ts +0 -29
- package/dist/components/ui/menu.js +0 -50
- package/dist/hooks/useApi.d.ts +0 -10
- package/dist/hooks/useApi.js +0 -11
- package/dist/hooks/useAudit.d.ts +0 -39
- package/dist/hooks/useAudit.js +0 -55
- package/dist/hooks/useAuth.d.ts +0 -1
- package/dist/hooks/useAuth.js +0 -4
- package/dist/hooks/useBilling.d.ts +0 -44
- package/dist/hooks/useBilling.js +0 -64
- package/dist/hooks/useLogin.d.ts +0 -10
- package/dist/hooks/useLogin.js +0 -39
- package/dist/hooks/useMembers.d.ts +0 -125
- package/dist/hooks/useMembers.js +0 -127
- package/dist/hooks/useNotificationPrefs.d.ts +0 -20
- package/dist/hooks/useNotificationPrefs.js +0 -42
- package/dist/hooks/usePasswordReset.d.ts +0 -5
- package/dist/hooks/usePasswordReset.js +0 -12
- package/dist/hooks/useSEO.d.ts +0 -6
- package/dist/hooks/useSEO.js +0 -14
- package/dist/hooks/useSessions.d.ts +0 -20
- package/dist/hooks/useSessions.js +0 -38
- package/dist/hooks/useSiteConfig.d.ts +0 -12
- package/dist/hooks/useSiteConfig.js +0 -11
- package/dist/hooks/useTokens.d.ts +0 -36
- package/dist/hooks/useTokens.js +0 -35
- package/dist/hooks/useUsage.d.ts +0 -20
- package/dist/hooks/useUsage.js +0 -21
- package/dist/hooks/useWorkspace.d.ts +0 -26
- package/dist/hooks/useWorkspace.js +0 -32
- package/dist/hooks/useZodForm.d.ts +0 -6
- package/dist/hooks/useZodForm.js +0 -6
- package/dist/hooks/ws.d.ts +0 -4
- package/dist/hooks/ws.js +0 -21
- package/dist/lib/perm.d.ts +0 -2
- package/dist/lib/perm.js +0 -7
- package/dist/lib/ws-query-bridge.d.ts +0 -7
- package/dist/lib/ws-query-bridge.js +0 -35
- package/dist/provider/PloykitProvider.d.ts +0 -50
- package/dist/provider/PloykitProvider.js +0 -240
- package/dist/realtime.d.ts +0 -3
- package/dist/realtime.js +0 -11
- /package/dist/components/ui/{Badge.js → badge.js} +0 -0
- /package/dist/components/ui/{Button.js → button.js} +0 -0
- /package/dist/components/ui/{Input.d.ts → input.d.ts} +0 -0
- /package/dist/components/ui/{Input.js → input.js} +0 -0
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
2
|
-
import { api } from '@ploykit/client';
|
|
3
|
-
import { queryKeys } from '../provider/PloykitProvider';
|
|
4
|
-
function normalize(data) {
|
|
5
|
-
const list = Array.isArray(data) ? data : data?.items;
|
|
6
|
-
return Array.isArray(list) ? list : [];
|
|
7
|
-
}
|
|
8
|
-
export function useSessions() {
|
|
9
|
-
const q = useQuery({
|
|
10
|
-
queryKey: queryKeys.sessions,
|
|
11
|
-
queryFn: async () => normalize(await api.get('/auth/sessions')),
|
|
12
|
-
});
|
|
13
|
-
return { sessions: q.data ?? [], loading: q.isPending, error: q.error, refetch: q.refetch };
|
|
14
|
-
}
|
|
15
|
-
export function useRevokeSession() {
|
|
16
|
-
const qc = useQueryClient();
|
|
17
|
-
const m = useMutation({
|
|
18
|
-
mutationFn: (id) => api.delete(`/auth/sessions/${id}`),
|
|
19
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.sessions }),
|
|
20
|
-
});
|
|
21
|
-
return {
|
|
22
|
-
revoke: (id) => m.mutateAsync(id),
|
|
23
|
-
loading: m.isPending,
|
|
24
|
-
error: m.error,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function useRevokeAllSessions() {
|
|
28
|
-
const qc = useQueryClient();
|
|
29
|
-
const m = useMutation({
|
|
30
|
-
mutationFn: () => api.delete('/auth/sessions'),
|
|
31
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.sessions }),
|
|
32
|
-
});
|
|
33
|
-
return {
|
|
34
|
-
revokeAll: () => m.mutateAsync(),
|
|
35
|
-
loading: m.isPending,
|
|
36
|
-
error: m.error,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export declare const SITE_CONFIG_QUERY_KEY: readonly ["site-config"];
|
|
2
|
-
export interface SiteConfig {
|
|
3
|
-
oauth_providers?: string[];
|
|
4
|
-
billing_channels?: string[];
|
|
5
|
-
banner_text?: string;
|
|
6
|
-
banner_kind?: string;
|
|
7
|
-
maintenance_mode?: string;
|
|
8
|
-
allow_signup?: string;
|
|
9
|
-
allowed_domains?: string;
|
|
10
|
-
mail_mode?: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function useSiteConfig(): import("@tanstack/react-query").UseQueryResult<SiteConfig, Error>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { useQuery } from '@tanstack/react-query';
|
|
2
|
-
import { api } from '@ploykit/client';
|
|
3
|
-
export const SITE_CONFIG_QUERY_KEY = ['site-config'];
|
|
4
|
-
export function useSiteConfig() {
|
|
5
|
-
return useQuery({
|
|
6
|
-
queryKey: SITE_CONFIG_QUERY_KEY,
|
|
7
|
-
queryFn: () => api.get('/config'),
|
|
8
|
-
staleTime: 5 * 60_000,
|
|
9
|
-
retry: false,
|
|
10
|
-
});
|
|
11
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { components } from '@ploykit/client';
|
|
2
|
-
export type PAT = components['schemas']['PAT'];
|
|
3
|
-
export type CreatePATResult = components['schemas']['CreatePATResponse'];
|
|
4
|
-
export declare function useTokens(): {
|
|
5
|
-
tokens: {
|
|
6
|
-
id: string;
|
|
7
|
-
name: string;
|
|
8
|
-
prefix: string;
|
|
9
|
-
expires_at?: string;
|
|
10
|
-
last_used_at?: string;
|
|
11
|
-
created_at: string;
|
|
12
|
-
}[];
|
|
13
|
-
loading: boolean;
|
|
14
|
-
error: Error | null;
|
|
15
|
-
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<{
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
prefix: string;
|
|
19
|
-
expires_at?: string;
|
|
20
|
-
last_used_at?: string;
|
|
21
|
-
created_at: string;
|
|
22
|
-
}[], Error>>;
|
|
23
|
-
};
|
|
24
|
-
export declare function useCreateToken(): {
|
|
25
|
-
create: (name: string, ttlHours?: number) => Promise<{
|
|
26
|
-
pat: components["schemas"]["PAT"];
|
|
27
|
-
token: string;
|
|
28
|
-
}>;
|
|
29
|
-
loading: boolean;
|
|
30
|
-
error: Error | null;
|
|
31
|
-
};
|
|
32
|
-
export declare function useRevokeToken(): {
|
|
33
|
-
revoke: (id: string) => Promise<void>;
|
|
34
|
-
loading: boolean;
|
|
35
|
-
error: Error | null;
|
|
36
|
-
};
|
package/dist/hooks/useTokens.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
3
|
-
import { api } from '@ploykit/client';
|
|
4
|
-
import { queryKeys } from '../provider/PloykitProvider';
|
|
5
|
-
export function useTokens() {
|
|
6
|
-
const q = useQuery({
|
|
7
|
-
queryKey: queryKeys.tokens,
|
|
8
|
-
queryFn: async () => {
|
|
9
|
-
const data = await api.get('/api/tokens');
|
|
10
|
-
return Array.isArray(data) ? data : [];
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
return { tokens: q.data ?? [], loading: q.isPending, error: q.error, refetch: q.refetch };
|
|
14
|
-
}
|
|
15
|
-
export function useCreateToken() {
|
|
16
|
-
const qc = useQueryClient();
|
|
17
|
-
const m = useMutation({
|
|
18
|
-
mutationFn: (v) => api.post('/api/tokens', v),
|
|
19
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.tokens }),
|
|
20
|
-
});
|
|
21
|
-
const create = useCallback((name, ttlHours) => m.mutateAsync({ name, ttl_hours: ttlHours }), [m]);
|
|
22
|
-
return { create, loading: m.isPending, error: m.error };
|
|
23
|
-
}
|
|
24
|
-
export function useRevokeToken() {
|
|
25
|
-
const qc = useQueryClient();
|
|
26
|
-
const m = useMutation({
|
|
27
|
-
mutationFn: (id) => api.delete(`/api/tokens/${id}`),
|
|
28
|
-
onSuccess: () => qc.invalidateQueries({ queryKey: queryKeys.tokens }),
|
|
29
|
-
});
|
|
30
|
-
return {
|
|
31
|
-
revoke: (id) => m.mutateAsync(id),
|
|
32
|
-
loading: m.isPending,
|
|
33
|
-
error: m.error,
|
|
34
|
-
};
|
|
35
|
-
}
|
package/dist/hooks/useUsage.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { components } from '@ploykit/client';
|
|
2
|
-
export type PKUsageResp = components['schemas']['UsageResp'];
|
|
3
|
-
export type PKUsageItem = components['schemas']['UsageItem'];
|
|
4
|
-
export declare function useUsage(): {
|
|
5
|
-
wsId: string;
|
|
6
|
-
usage: {
|
|
7
|
-
workspace_id: string;
|
|
8
|
-
plan_code: string;
|
|
9
|
-
period: string;
|
|
10
|
-
items: components["schemas"]["UsageItem"][];
|
|
11
|
-
} | null;
|
|
12
|
-
loading: boolean;
|
|
13
|
-
error: Error | null;
|
|
14
|
-
refetch: (options?: import("@tanstack/query-core").RefetchOptions) => Promise<import("@tanstack/query-core").QueryObserverResult<{
|
|
15
|
-
workspace_id: string;
|
|
16
|
-
plan_code: string;
|
|
17
|
-
period: string;
|
|
18
|
-
items: components["schemas"]["UsageItem"][];
|
|
19
|
-
}, Error>>;
|
|
20
|
-
};
|
package/dist/hooks/useUsage.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useQuery } from '@tanstack/react-query';
|
|
2
|
-
import { useApi } from './useApi';
|
|
3
|
-
import { useWorkspace } from './useWorkspace';
|
|
4
|
-
import { queryKeys } from '../provider/PloykitProvider';
|
|
5
|
-
export function useUsage() {
|
|
6
|
-
const { current } = useWorkspace();
|
|
7
|
-
const api = useApi();
|
|
8
|
-
const wsId = current?.id ?? '';
|
|
9
|
-
const q = useQuery({
|
|
10
|
-
queryKey: queryKeys.usage(wsId),
|
|
11
|
-
queryFn: () => api.get('/api/usage'),
|
|
12
|
-
enabled: !!wsId,
|
|
13
|
-
});
|
|
14
|
-
return {
|
|
15
|
-
wsId,
|
|
16
|
-
usage: wsId ? (q.data ?? null) : null,
|
|
17
|
-
loading: !!wsId && q.isPending,
|
|
18
|
-
error: q.error,
|
|
19
|
-
refetch: q.refetch,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { type PKWorkspace } from '../provider/PloykitProvider';
|
|
2
|
-
export declare function useWorkspace(): import("../provider/PloykitProvider").WorkspaceContextValue;
|
|
3
|
-
export declare function useWorkspaceSwitch(): {
|
|
4
|
-
current: ({
|
|
5
|
-
id: string;
|
|
6
|
-
slug: string;
|
|
7
|
-
name: string;
|
|
8
|
-
plan_code: string;
|
|
9
|
-
created_at: string;
|
|
10
|
-
} & {
|
|
11
|
-
role: "owner" | "admin" | "member";
|
|
12
|
-
}) | null;
|
|
13
|
-
list: ({
|
|
14
|
-
id: string;
|
|
15
|
-
slug: string;
|
|
16
|
-
name: string;
|
|
17
|
-
plan_code: string;
|
|
18
|
-
created_at: string;
|
|
19
|
-
} & {
|
|
20
|
-
role: "owner" | "admin" | "member";
|
|
21
|
-
})[];
|
|
22
|
-
switchTo: (id: string) => void;
|
|
23
|
-
create: (name: string, slug: string) => Promise<PKWorkspace | null>;
|
|
24
|
-
creating: boolean;
|
|
25
|
-
error: unknown;
|
|
26
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useCallback, useState } from 'react';
|
|
2
|
-
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
-
import { api } from '@ploykit/client';
|
|
4
|
-
import { useAuthCtx, useWorkspaceCtx, queryKeys, } from '../provider/PloykitProvider';
|
|
5
|
-
export function useWorkspace() {
|
|
6
|
-
return useWorkspaceCtx();
|
|
7
|
-
}
|
|
8
|
-
export function useWorkspaceSwitch() {
|
|
9
|
-
const { workspaces } = useAuthCtx();
|
|
10
|
-
const { current, switchTo } = useWorkspaceCtx();
|
|
11
|
-
const qc = useQueryClient();
|
|
12
|
-
const [creating, setCreating] = useState(false);
|
|
13
|
-
const [error, setError] = useState(null);
|
|
14
|
-
const create = useCallback(async (name, slug) => {
|
|
15
|
-
setCreating(true);
|
|
16
|
-
setError(null);
|
|
17
|
-
try {
|
|
18
|
-
const ws = await api.post('/api/workspaces', { name, slug });
|
|
19
|
-
await qc.invalidateQueries({ queryKey: queryKeys.workspace });
|
|
20
|
-
switchTo(ws.id);
|
|
21
|
-
return ws;
|
|
22
|
-
}
|
|
23
|
-
catch (e) {
|
|
24
|
-
setError(e);
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
finally {
|
|
28
|
-
setCreating(false);
|
|
29
|
-
}
|
|
30
|
-
}, [qc, switchTo]);
|
|
31
|
-
return { current, list: workspaces, switchTo, create, creating, error };
|
|
32
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type FieldValues, type UseFormProps, type UseFormReturn } from 'react-hook-form';
|
|
2
|
-
import type { ZodSchema } from 'zod';
|
|
3
|
-
export interface ZodFormOptions<T extends FieldValues> extends UseFormProps<T> {
|
|
4
|
-
schema: ZodSchema<T, T>;
|
|
5
|
-
}
|
|
6
|
-
export declare function useZodForm<T extends FieldValues>(opts: ZodFormOptions<T>): UseFormReturn<T>;
|
package/dist/hooks/useZodForm.js
DELETED
package/dist/hooks/ws.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { FrameHandler, ScopePrefix, WsClient, WsStatus } from '@ploykit/client';
|
|
2
|
-
export declare function useWsStatus(client: WsClient): WsStatus;
|
|
3
|
-
export declare function useWsScope(prefix: ScopePrefix, id: string | undefined, client: WsClient): void;
|
|
4
|
-
export declare function useWsFrame(type: string, handler: FrameHandler, client: WsClient): void;
|
package/dist/hooks/ws.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useSyncExternalStore } from 'react';
|
|
2
|
-
export function useWsStatus(client) {
|
|
3
|
-
return useSyncExternalStore((cb) => client.onStatus(cb), () => client.status, () => 'idle');
|
|
4
|
-
}
|
|
5
|
-
export function useWsScope(prefix, id, client) {
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
if (!id)
|
|
8
|
-
return;
|
|
9
|
-
return client.subscribe(prefix, id);
|
|
10
|
-
}, [prefix, id, client]);
|
|
11
|
-
}
|
|
12
|
-
export function useWsFrame(type, handler, client) {
|
|
13
|
-
const ref = useRef(handler);
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
ref.current = handler;
|
|
16
|
-
});
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
const dispatch = (frame) => ref.current(frame);
|
|
19
|
-
return client.on(type, dispatch);
|
|
20
|
-
}, [type, client]);
|
|
21
|
-
}
|
package/dist/lib/perm.d.ts
DELETED
package/dist/lib/perm.js
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { QueryClient, QueryKey } from '@tanstack/react-query';
|
|
2
|
-
import type { WsClient } from '@ploykit/client';
|
|
3
|
-
export interface WsInvalidationRule {
|
|
4
|
-
match: string | RegExp;
|
|
5
|
-
invalidate: readonly QueryKey[];
|
|
6
|
-
}
|
|
7
|
-
export declare function bridgeWsToQuery(ws: WsClient, queryClient: QueryClient, rules: readonly WsInvalidationRule[]): () => void;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
function ruleMatches(rule, type) {
|
|
2
|
-
if (typeof rule.match === 'string')
|
|
3
|
-
return rule.match === type;
|
|
4
|
-
rule.match.lastIndex = 0;
|
|
5
|
-
return rule.match.test(type);
|
|
6
|
-
}
|
|
7
|
-
export function bridgeWsToQuery(ws, queryClient, rules) {
|
|
8
|
-
let sawOpen = false;
|
|
9
|
-
const offStatus = ws.onStatus((status) => {
|
|
10
|
-
if (status !== 'open')
|
|
11
|
-
return;
|
|
12
|
-
if (!sawOpen) {
|
|
13
|
-
sawOpen = true;
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
for (const rule of rules) {
|
|
17
|
-
for (const key of rule.invalidate) {
|
|
18
|
-
queryClient.invalidateQueries({ queryKey: key });
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
const offFrame = ws.on('*', (frame) => {
|
|
23
|
-
for (const rule of rules) {
|
|
24
|
-
if (!ruleMatches(rule, frame.type))
|
|
25
|
-
continue;
|
|
26
|
-
for (const key of rule.invalidate) {
|
|
27
|
-
queryClient.invalidateQueries({ queryKey: key });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
return () => {
|
|
32
|
-
offStatus();
|
|
33
|
-
offFrame();
|
|
34
|
-
};
|
|
35
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
2
|
-
import { QueryClient } from '@tanstack/react-query';
|
|
3
|
-
import type { APIUser, APIWorkspace, APISubscription, APIOrder, APIPlan } from '@ploykit/client';
|
|
4
|
-
export declare const queryKeys: {
|
|
5
|
-
auth: readonly ["auth"];
|
|
6
|
-
me: readonly ["auth", "me"];
|
|
7
|
-
sessions: readonly ["auth", "sessions"];
|
|
8
|
-
tokens: readonly ["auth", "tokens"];
|
|
9
|
-
workspace: readonly ["workspace"];
|
|
10
|
-
workspaceList: readonly ["workspace", "list"];
|
|
11
|
-
members: (wsId: string) => readonly ["workspace", string, "members"];
|
|
12
|
-
invitations: (wsId: string) => readonly ["workspace", string, "invitations"];
|
|
13
|
-
shareLinks: (wsId: string) => readonly ["workspace", string, "share-links"];
|
|
14
|
-
myInvitations: readonly ["workspace", "my-invitations"];
|
|
15
|
-
audit: (wsId: string, q: object) => readonly ["audit", string, object];
|
|
16
|
-
usage: (wsId: string) => readonly ["usage", string];
|
|
17
|
-
billing: readonly ["billing"];
|
|
18
|
-
billingSubscription: (workspaceId: string) => readonly ["billing", "subscription", string];
|
|
19
|
-
billingPlans: readonly ["billing", "plans"];
|
|
20
|
-
notifications: readonly ["notifications"];
|
|
21
|
-
notificationPrefs: readonly ["notifications", "preferences"];
|
|
22
|
-
webhooks: (wsId: string) => readonly ["webhooks", string];
|
|
23
|
-
admin: readonly ["admin"];
|
|
24
|
-
};
|
|
25
|
-
export type PKUser = APIUser;
|
|
26
|
-
export type PKWorkspace = APIWorkspace;
|
|
27
|
-
export type PKSubscription = APISubscription;
|
|
28
|
-
export type PKOrder = APIOrder;
|
|
29
|
-
export type PKPlan = APIPlan;
|
|
30
|
-
export interface AuthContextValue {
|
|
31
|
-
user: PKUser | null;
|
|
32
|
-
workspaces: PKWorkspace[];
|
|
33
|
-
loading: boolean;
|
|
34
|
-
error: unknown;
|
|
35
|
-
refresh(): Promise<void>;
|
|
36
|
-
logout(): Promise<void>;
|
|
37
|
-
}
|
|
38
|
-
export declare const AuthContext: import("react").Context<AuthContextValue | null>;
|
|
39
|
-
export interface WorkspaceContextValue {
|
|
40
|
-
current: PKWorkspace | null;
|
|
41
|
-
switchTo(id: string): void;
|
|
42
|
-
clear(): void;
|
|
43
|
-
}
|
|
44
|
-
export declare const WorkspaceContext: import("react").Context<WorkspaceContextValue | null>;
|
|
45
|
-
export declare function useAuthCtx(): AuthContextValue;
|
|
46
|
-
export declare function useWorkspaceCtx(): WorkspaceContextValue;
|
|
47
|
-
export declare function PloykitProvider({ children, queryClient }: {
|
|
48
|
-
children: ReactNode;
|
|
49
|
-
queryClient?: QueryClient;
|
|
50
|
-
}): import("react").JSX.Element;
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
3
|
-
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { api, ApiError, setWorkspaceIdProvider } from '@ploykit/client';
|
|
5
|
-
export const queryKeys = {
|
|
6
|
-
auth: ['auth'],
|
|
7
|
-
me: ['auth', 'me'],
|
|
8
|
-
sessions: ['auth', 'sessions'],
|
|
9
|
-
tokens: ['auth', 'tokens'],
|
|
10
|
-
workspace: ['workspace'],
|
|
11
|
-
workspaceList: ['workspace', 'list'],
|
|
12
|
-
members: (wsId) => ['workspace', wsId, 'members'],
|
|
13
|
-
invitations: (wsId) => ['workspace', wsId, 'invitations'],
|
|
14
|
-
shareLinks: (wsId) => ['workspace', wsId, 'share-links'],
|
|
15
|
-
myInvitations: ['workspace', 'my-invitations'],
|
|
16
|
-
audit: (wsId, q) => ['audit', wsId, q],
|
|
17
|
-
usage: (wsId) => ['usage', wsId],
|
|
18
|
-
billing: ['billing'],
|
|
19
|
-
billingSubscription: (workspaceId) => ['billing', 'subscription', workspaceId],
|
|
20
|
-
billingPlans: ['billing', 'plans'],
|
|
21
|
-
notifications: ['notifications'], // 元组:可作前缀失效(原为裸字符串)
|
|
22
|
-
notificationPrefs: ['notifications', 'preferences'],
|
|
23
|
-
webhooks: (wsId) => ['webhooks', wsId],
|
|
24
|
-
admin: ['admin'],
|
|
25
|
-
};
|
|
26
|
-
function createDefaultQueryClient() {
|
|
27
|
-
return new QueryClient({
|
|
28
|
-
defaultOptions: {
|
|
29
|
-
queries: {
|
|
30
|
-
staleTime: 30_000,
|
|
31
|
-
retry: (failureCount, error) => {
|
|
32
|
-
if (error instanceof ApiError && error.status >= 400 && error.status < 500)
|
|
33
|
-
return false;
|
|
34
|
-
return failureCount < 1;
|
|
35
|
-
},
|
|
36
|
-
refetchOnWindowFocus: false,
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
const WS_URL_PARAM = 'ws';
|
|
42
|
-
const wsStorageKey = (userId) => `pk.ws.${userId}`;
|
|
43
|
-
function readWsIdFromUrl() {
|
|
44
|
-
if (typeof window === 'undefined')
|
|
45
|
-
return null;
|
|
46
|
-
try {
|
|
47
|
-
return new URLSearchParams(window.location.search).get(WS_URL_PARAM) || null;
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function writeWsIdToUrl(id) {
|
|
54
|
-
if (typeof window === 'undefined')
|
|
55
|
-
return;
|
|
56
|
-
try {
|
|
57
|
-
const url = new URL(window.location.href);
|
|
58
|
-
url.searchParams.set(WS_URL_PARAM, id);
|
|
59
|
-
window.history.replaceState(window.history.state, '', url.href);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
/* 受限环境降级:仅不写 URL,上下文本体不受影响 */
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
function removeWsIdFromUrl() {
|
|
66
|
-
if (typeof window === 'undefined')
|
|
67
|
-
return;
|
|
68
|
-
try {
|
|
69
|
-
const url = new URL(window.location.href);
|
|
70
|
-
if (!url.searchParams.has(WS_URL_PARAM))
|
|
71
|
-
return;
|
|
72
|
-
url.searchParams.delete(WS_URL_PARAM);
|
|
73
|
-
window.history.replaceState(window.history.state, '', url.href);
|
|
74
|
-
}
|
|
75
|
-
catch {
|
|
76
|
-
/* 同上:静默降级 */
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function readStoredWsId(userId) {
|
|
80
|
-
if (typeof window === 'undefined')
|
|
81
|
-
return null;
|
|
82
|
-
try {
|
|
83
|
-
return window.localStorage.getItem(wsStorageKey(userId)) || null;
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function writeStoredWsId(userId, id) {
|
|
90
|
-
if (typeof window === 'undefined')
|
|
91
|
-
return;
|
|
92
|
-
try {
|
|
93
|
-
window.localStorage.setItem(wsStorageKey(userId), id);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
/* localStorage 不可用(隐私模式/配额):降级为内存 + URL 两层 */
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function removeStoredWsId(userId) {
|
|
100
|
-
if (typeof window === 'undefined')
|
|
101
|
-
return;
|
|
102
|
-
try {
|
|
103
|
-
window.localStorage.removeItem(wsStorageKey(userId));
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
/* 静默降级 */
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
export const AuthContext = createContext(null);
|
|
110
|
-
export const WorkspaceContext = createContext(null);
|
|
111
|
-
export function useAuthCtx() {
|
|
112
|
-
const ctx = useContext(AuthContext);
|
|
113
|
-
if (!ctx)
|
|
114
|
-
throw new Error('must be used within PloykitProvider');
|
|
115
|
-
return ctx;
|
|
116
|
-
}
|
|
117
|
-
export function useWorkspaceCtx() {
|
|
118
|
-
const ctx = useContext(WorkspaceContext);
|
|
119
|
-
if (!ctx)
|
|
120
|
-
throw new Error('must be used within PloykitProvider');
|
|
121
|
-
return ctx;
|
|
122
|
-
}
|
|
123
|
-
export function PloykitProvider({ children, queryClient }) {
|
|
124
|
-
const [qc] = useState(() => queryClient ?? createDefaultQueryClient());
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
qc.setQueryDefaults(queryKeys.admin, { staleTime: 0 });
|
|
127
|
-
}, [qc]);
|
|
128
|
-
return (_jsx(QueryClientProvider, { client: qc, children: _jsx(AuthLayer, { children: _jsx(WorkspaceLayer, { children: children }) }) }));
|
|
129
|
-
}
|
|
130
|
-
function AuthLayer({ children }) {
|
|
131
|
-
const qc = useQueryClient();
|
|
132
|
-
const meQ = useQuery({
|
|
133
|
-
queryKey: queryKeys.me,
|
|
134
|
-
queryFn: () => api.get('/auth/me').catch((err) => {
|
|
135
|
-
if (err instanceof ApiError && err.status === 401)
|
|
136
|
-
return null;
|
|
137
|
-
throw err;
|
|
138
|
-
}),
|
|
139
|
-
});
|
|
140
|
-
const wsQ = useQuery({
|
|
141
|
-
queryKey: queryKeys.workspaceList,
|
|
142
|
-
queryFn: () => api.get('/api/workspaces').catch((err) => {
|
|
143
|
-
if (err instanceof ApiError && err.status === 401)
|
|
144
|
-
return [];
|
|
145
|
-
throw err;
|
|
146
|
-
}),
|
|
147
|
-
});
|
|
148
|
-
const user = meQ.data ?? null;
|
|
149
|
-
const workspaces = Array.isArray(wsQ.data) ? wsQ.data : [];
|
|
150
|
-
const refresh = useCallback(async () => {
|
|
151
|
-
await Promise.all([
|
|
152
|
-
qc.invalidateQueries({ queryKey: queryKeys.auth }),
|
|
153
|
-
qc.invalidateQueries({ queryKey: queryKeys.workspace }),
|
|
154
|
-
]);
|
|
155
|
-
}, [qc]);
|
|
156
|
-
const logout = useCallback(async () => {
|
|
157
|
-
const me = qc.getQueryData(queryKeys.me);
|
|
158
|
-
if (me?.id)
|
|
159
|
-
removeStoredWsId(me.id);
|
|
160
|
-
await api.post('/auth/logout').catch(() => { });
|
|
161
|
-
qc.setQueryData(queryKeys.me, null);
|
|
162
|
-
qc.setQueryData(queryKeys.workspaceList, []);
|
|
163
|
-
qc.removeQueries();
|
|
164
|
-
}, [qc]);
|
|
165
|
-
const value = useMemo(() => ({
|
|
166
|
-
user,
|
|
167
|
-
workspaces,
|
|
168
|
-
loading: meQ.isPending || wsQ.isPending,
|
|
169
|
-
error: meQ.error ?? wsQ.error ?? null,
|
|
170
|
-
refresh,
|
|
171
|
-
logout,
|
|
172
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
173
|
-
}), [user, workspaces, meQ.isPending, wsQ.isPending, meQ.error, wsQ.error, refresh, logout]);
|
|
174
|
-
return _jsx(AuthContext.Provider, { value: value, children: children });
|
|
175
|
-
}
|
|
176
|
-
function WorkspaceLayer({ children }) {
|
|
177
|
-
const { user, workspaces } = useAuthCtx();
|
|
178
|
-
const [currentId, setCurrentId] = useState(null);
|
|
179
|
-
const userId = user?.id;
|
|
180
|
-
useEffect(() => {
|
|
181
|
-
if (!user || workspaces.length === 0 || currentId)
|
|
182
|
-
return;
|
|
183
|
-
const uid = user.id;
|
|
184
|
-
const candidate = readWsIdFromUrl() ?? (uid ? readStoredWsId(uid) : null);
|
|
185
|
-
if (candidate && workspaces.some((ws) => ws.id === candidate)) {
|
|
186
|
-
setCurrentId(candidate);
|
|
187
|
-
if (uid)
|
|
188
|
-
writeStoredWsId(uid, candidate);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
if (candidate) {
|
|
192
|
-
if (uid)
|
|
193
|
-
removeStoredWsId(uid);
|
|
194
|
-
removeWsIdFromUrl();
|
|
195
|
-
}
|
|
196
|
-
setCurrentId(workspaces[0].id);
|
|
197
|
-
}, [user, workspaces, currentId]);
|
|
198
|
-
useEffect(() => {
|
|
199
|
-
if (currentId && !workspaces.some((ws) => ws.id === currentId)) {
|
|
200
|
-
setCurrentId(workspaces[0]?.id ?? null);
|
|
201
|
-
if (userId)
|
|
202
|
-
removeStoredWsId(userId);
|
|
203
|
-
removeWsIdFromUrl();
|
|
204
|
-
}
|
|
205
|
-
}, [workspaces, currentId, userId]);
|
|
206
|
-
useEffect(() => {
|
|
207
|
-
if (typeof window === 'undefined')
|
|
208
|
-
return;
|
|
209
|
-
const onPopState = () => {
|
|
210
|
-
const urlId = readWsIdFromUrl();
|
|
211
|
-
if (!urlId)
|
|
212
|
-
return;
|
|
213
|
-
setCurrentId((prev) => (prev === urlId ? prev : urlId));
|
|
214
|
-
if (userId)
|
|
215
|
-
writeStoredWsId(userId, urlId);
|
|
216
|
-
};
|
|
217
|
-
window.addEventListener('popstate', onPopState);
|
|
218
|
-
return () => window.removeEventListener('popstate', onPopState);
|
|
219
|
-
}, [userId]);
|
|
220
|
-
const current = workspaces.find((ws) => ws.id === currentId) ?? null;
|
|
221
|
-
setWorkspaceIdProvider(() => current?.id ?? null);
|
|
222
|
-
const switchTo = useCallback((id) => {
|
|
223
|
-
setCurrentId(id);
|
|
224
|
-
if (userId)
|
|
225
|
-
writeStoredWsId(userId, id);
|
|
226
|
-
writeWsIdToUrl(id);
|
|
227
|
-
}, [userId]);
|
|
228
|
-
const clear = useCallback(() => {
|
|
229
|
-
setCurrentId(null);
|
|
230
|
-
if (userId)
|
|
231
|
-
removeStoredWsId(userId);
|
|
232
|
-
removeWsIdFromUrl();
|
|
233
|
-
}, [userId]);
|
|
234
|
-
const value = useMemo(() => ({
|
|
235
|
-
current,
|
|
236
|
-
switchTo,
|
|
237
|
-
clear,
|
|
238
|
-
}), [current, switchTo, clear]);
|
|
239
|
-
return _jsx(WorkspaceContext.Provider, { value: value, children: children });
|
|
240
|
-
}
|
package/dist/realtime.d.ts
DELETED
package/dist/realtime.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { WsClient } from '@ploykit/client';
|
|
2
|
-
export function defaultWsUrl(workspaceId) {
|
|
3
|
-
const proto = typeof location === 'undefined' ? 'ws' : location.protocol === 'https:' ? 'wss' : 'ws';
|
|
4
|
-
const host = typeof location === 'undefined' ? 'localhost' : location.host;
|
|
5
|
-
return workspaceId
|
|
6
|
-
? `${proto}://${host}/ws?workspace_id=${encodeURIComponent(workspaceId)}`
|
|
7
|
-
: `${proto}://${host}/ws`;
|
|
8
|
-
}
|
|
9
|
-
export function createWsClient(url, options) {
|
|
10
|
-
return new WsClient({ ...options, url });
|
|
11
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|