- pgSchema "mesh" with 4 tables isolating the peer mesh domain - Enums: visibility, transport, tier, role - audit_log is metadata-only (E2E encryption enforced at broker/client) - Cascade on mesh delete, soft-delete via archivedAt/revokedAt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
184 lines
5.2 KiB
TypeScript
184 lines
5.2 KiB
TypeScript
import {
|
|
getInvitationsResponseSchema,
|
|
getMembersResponseSchema,
|
|
} from "@turbostarter/api/schema";
|
|
import { handle } from "@turbostarter/api/utils";
|
|
|
|
import { appConfig } from "~/config/app";
|
|
import { pathsConfig } from "~/config/paths";
|
|
import { api } from "~/lib/api/client";
|
|
import { authClient } from "~/lib/auth/client";
|
|
|
|
import type { InferRequestType } from "hono/client";
|
|
|
|
const KEY = "organizations";
|
|
|
|
const queries = {
|
|
get: (params: { slug: string } | { id: string }) => ({
|
|
queryKey: [KEY, params],
|
|
queryFn: () =>
|
|
authClient.organization.getFullOrganization({
|
|
query:
|
|
"id" in params
|
|
? { organizationId: params.id }
|
|
: { organizationSlug: params.slug },
|
|
fetchOptions: {
|
|
throw: true,
|
|
},
|
|
}),
|
|
}),
|
|
members: {
|
|
getIsOnlyOwner: ({ id }: { id: string }) => ({
|
|
queryKey: [...queries.get({ id }).queryKey, "members", "is-only-owner"],
|
|
queryFn: () =>
|
|
handle(api.organizations[":id"].members["is-only-owner"].$get)({
|
|
param: { id },
|
|
}),
|
|
}),
|
|
getAll: ({
|
|
id,
|
|
...query
|
|
}: InferRequestType<
|
|
(typeof api.organizations)[":id"]["members"]["$get"]
|
|
>["query"] & { id: string }) => ({
|
|
queryKey: [...queries.get({ id }).queryKey, "members", query],
|
|
queryFn: () =>
|
|
handle(api.organizations[":id"].members.$get, {
|
|
schema: getMembersResponseSchema,
|
|
})({
|
|
query,
|
|
param: {
|
|
id,
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
invitations: {
|
|
getAll: ({
|
|
id,
|
|
...query
|
|
}: InferRequestType<
|
|
(typeof api.organizations)[":id"]["invitations"]["$get"]
|
|
>["query"] & { id: string }) => ({
|
|
queryKey: [...queries.get({ id }).queryKey, "invitations", query],
|
|
queryFn: () =>
|
|
handle(api.organizations[":id"].invitations.$get, {
|
|
schema: getInvitationsResponseSchema,
|
|
})({
|
|
query,
|
|
param: {
|
|
id,
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
};
|
|
|
|
const mutations = {
|
|
getSlug: {
|
|
mutationKey: [KEY, "slug"],
|
|
mutationFn: (data: InferRequestType<typeof api.organizations.slug.$get>) =>
|
|
handle(api.organizations.slug.$get)(data),
|
|
},
|
|
setActive: {
|
|
mutationKey: [KEY, "active"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.setActive>[0],
|
|
) => authClient.organization.setActive(params),
|
|
},
|
|
create: {
|
|
mutationKey: [KEY, "create"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.create>[0],
|
|
) =>
|
|
authClient.organization.create({
|
|
...params,
|
|
fetchOptions: { throw: true },
|
|
}),
|
|
},
|
|
update: {
|
|
mutationKey: [KEY, "update"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.update>[0],
|
|
) => authClient.organization.update(params),
|
|
},
|
|
delete: {
|
|
mutationKey: [KEY, "delete"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.delete>[0],
|
|
) => authClient.organization.delete(params),
|
|
},
|
|
leave: {
|
|
mutationKey: [KEY, "members", "leave"],
|
|
mutationFn: (params: Parameters<typeof authClient.organization.leave>[0]) =>
|
|
authClient.organization.leave(params),
|
|
},
|
|
members: {
|
|
remove: {
|
|
mutationKey: [KEY, "members", "remove"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.removeMember>[0],
|
|
) => authClient.organization.removeMember(params),
|
|
},
|
|
invite: {
|
|
mutationKey: [KEY, "members", "invite"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.inviteMember>[0],
|
|
) =>
|
|
authClient.organization.inviteMember(params, {
|
|
headers: {
|
|
"x-url": new URL(pathsConfig.auth.join, appConfig.url).toString(),
|
|
},
|
|
}),
|
|
},
|
|
updateRole: {
|
|
mutationKey: [KEY, "members", "update-role"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.updateMemberRole>[0],
|
|
) => authClient.organization.updateMemberRole(params),
|
|
},
|
|
},
|
|
invitations: {
|
|
accept: {
|
|
mutationKey: [KEY, "invitations", "accept"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.acceptInvitation>[0],
|
|
) => authClient.organization.acceptInvitation(params),
|
|
},
|
|
reject: {
|
|
mutationKey: [KEY, "invitations", "reject"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.rejectInvitation>[0],
|
|
) => authClient.organization.rejectInvitation(params),
|
|
},
|
|
cancel: {
|
|
mutationKey: [KEY, "invitations", "cancel"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.cancelInvitation>[0],
|
|
) => authClient.organization.cancelInvitation(params),
|
|
},
|
|
resend: {
|
|
mutationKey: [KEY, "invitations", "resend"],
|
|
mutationFn: (
|
|
params: Parameters<typeof authClient.organization.inviteMember>[0],
|
|
) =>
|
|
authClient.organization.inviteMember(
|
|
{
|
|
...params,
|
|
resend: true,
|
|
},
|
|
{
|
|
headers: {
|
|
"x-url": new URL(pathsConfig.auth.join, appConfig.url).toString(),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
},
|
|
};
|
|
|
|
export const organization = {
|
|
queries,
|
|
mutations,
|
|
} as const;
|