mirror of https://github.com/buster-so/buster.git
move enum types
This commit is contained in:
parent
87ea87e963
commit
ffeee17365
|
@ -19,7 +19,8 @@
|
|||
{ "path": "../packages/vitest-config" },
|
||||
{ "path": "../packages/web-tools" },
|
||||
{ "path": "../packages/sandbox" },
|
||||
{ "path": "../packages/env-utils" }
|
||||
{ "path": "../packages/env-utils" },
|
||||
{ "path": "../packages/server-utils" }
|
||||
],
|
||||
"settings": {
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
|
|
|
@ -742,7 +742,7 @@ impl FromSql<sql_types::MessageFeedbackEnum, Pg> for MessageFeedback {
|
|||
Serialize,
|
||||
)]
|
||||
#[diesel(sql_type = sql_types::WorkspaceSharingEnum)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum WorkspaceSharing {
|
||||
#[serde(alias = "none")]
|
||||
None,
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { getUserOrganizationId, updateReport } from '@buster/database';
|
||||
import {
|
||||
type ShareUpdateRequest,
|
||||
ShareUpdateRequestSchema,
|
||||
type ShareUpdateResponse,
|
||||
type UpdateReportResponse,
|
||||
} from '@buster/server-shared/reports';
|
||||
import type { ShareUpdateResponse, UpdateReportResponse } from '@buster/server-shared/reports';
|
||||
import { type ShareUpdateRequest, ShareUpdateRequestSchema } from '@buster/server-shared/share';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { Hono } from 'hono';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import type { ShareAssetType } from '@buster/server-shared/share';
|
||||
import type { BusterCollection, BusterCollectionListItem } from '@/api/asset_interfaces/collection';
|
||||
import type {
|
||||
ShareDeleteRequest,
|
||||
ShareUpdateRequest
|
||||
} from '@/api/asset_interfaces/shared_interfaces';
|
||||
import mainApi from '@/api/buster_rest/instances';
|
||||
import { SharePostRequest } from '@buster/server-shared/share';
|
||||
import type { ShareDeleteRequest, ShareUpdateRequest } from '@buster/server-shared/share';
|
||||
|
||||
export const collectionsGetList = async (params: {
|
||||
/** Current page number (1-based indexing) */
|
||||
|
|
|
@ -3,10 +3,7 @@ import type {
|
|||
BusterDashboardResponse,
|
||||
DashboardConfig
|
||||
} from '@/api/asset_interfaces/dashboard';
|
||||
import type {
|
||||
ShareDeleteRequest,
|
||||
ShareUpdateRequest
|
||||
} from '@/api/asset_interfaces/shared_interfaces';
|
||||
import type { ShareDeleteRequest, ShareUpdateRequest } from '@buster/server-shared/share';
|
||||
import mainApi from '@/api/buster_rest/instances';
|
||||
import { serverFetch } from '@/api/createServerInstance';
|
||||
import { SharePostRequest } from '@buster/server-shared/share';
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import type {
|
||||
BulkUpdateMetricVerificationStatusRequest,
|
||||
BulkUpdateMetricVerificationStatusResponse,
|
||||
ShareDeleteRequest,
|
||||
ShareUpdateRequest,
|
||||
DeleteMetricRequest,
|
||||
DeleteMetricResponse,
|
||||
DuplicateMetricRequest,
|
||||
|
@ -18,6 +16,7 @@ import type {
|
|||
UpdateMetricResponse,
|
||||
ShareUpdateResponse
|
||||
} from '@buster/server-shared/metrics';
|
||||
import type { ShareDeleteRequest, ShareUpdateRequest } from '@buster/server-shared/share';
|
||||
import { serverFetch } from '@/api/createServerInstance';
|
||||
import { mainApi } from '../instances';
|
||||
import { SharePostRequest } from '@buster/server-shared/share';
|
||||
|
|
|
@ -10,7 +10,6 @@ import { useMemoizedFn } from '@/hooks';
|
|||
import { queryKeys } from '@/api/query_keys';
|
||||
import type { RustApiError } from '../errors';
|
||||
import type {
|
||||
GetReportsListResponse,
|
||||
GetReportIndividualResponse,
|
||||
UpdateReportRequest,
|
||||
UpdateReportResponse
|
||||
|
@ -129,9 +128,6 @@ export const useUpdateReport = () => {
|
|||
queryKeys.reportsGetReport(reportId).queryKey,
|
||||
create(previousReport, (draft) => {
|
||||
if (data.name !== undefined) draft.name = data.name;
|
||||
if (data.description !== undefined) draft.description = data.description;
|
||||
if (data.publicly_accessible !== undefined)
|
||||
draft.publicly_accessible = data.publicly_accessible;
|
||||
if (data.content !== undefined) draft.content = data.content;
|
||||
})
|
||||
);
|
||||
|
|
|
@ -64,16 +64,20 @@ export const AccessDropdown: React.FC<AccessDropdownProps> = React.memo(
|
|||
|
||||
// Using a type-safe switch to handle all ShareRole values
|
||||
switch (value) {
|
||||
case 'fullAccess':
|
||||
case 'full_access':
|
||||
return 'Full access';
|
||||
case 'canEdit':
|
||||
case 'can_edit':
|
||||
return 'Can edit';
|
||||
case 'canView':
|
||||
case 'can_view':
|
||||
return 'Can view';
|
||||
case 'owner':
|
||||
return 'Owner';
|
||||
case 'remove':
|
||||
return 'Remove';
|
||||
case 'viewer':
|
||||
return 'Viewer';
|
||||
case 'can_filter':
|
||||
return 'Can filter';
|
||||
case 'none':
|
||||
return 'Not shared';
|
||||
default:
|
||||
|
@ -86,7 +90,13 @@ export const AccessDropdown: React.FC<AccessDropdownProps> = React.memo(
|
|||
if (value === 'remove' || value === 'notShared') {
|
||||
onChangeShareLevel?.(null);
|
||||
} else {
|
||||
onChangeShareLevel?.(value as ShareRole);
|
||||
if (props.type === 'workspace') {
|
||||
(onChangeShareLevel as (level: WorkspaceShareRole | null) => void)?.(
|
||||
value as WorkspaceShareRole
|
||||
);
|
||||
} else {
|
||||
(onChangeShareLevel as (level: ShareRole | null) => void)?.(value as ShareRole);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -122,17 +132,17 @@ AccessDropdown.displayName = 'AccessDropdown';
|
|||
|
||||
const metricItems: DropdownItem<ShareRole>[] = [
|
||||
{
|
||||
value: 'fullAccess',
|
||||
value: 'full_access',
|
||||
label: 'Full access',
|
||||
secondaryLabel: 'Can edit and share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canEdit',
|
||||
value: 'can_edit',
|
||||
label: 'Can edit',
|
||||
secondaryLabel: 'Can edit but not share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canView',
|
||||
value: 'can_view',
|
||||
label: 'Can view',
|
||||
secondaryLabel: 'Can view asset but not edit.'
|
||||
}
|
||||
|
@ -140,17 +150,17 @@ const metricItems: DropdownItem<ShareRole>[] = [
|
|||
|
||||
const dashboardItems: DropdownItem<ShareRole>[] = [
|
||||
{
|
||||
value: 'fullAccess',
|
||||
value: 'full_access',
|
||||
label: 'Full access',
|
||||
secondaryLabel: 'Can edit and share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canEdit',
|
||||
value: 'can_edit',
|
||||
label: 'Can edit',
|
||||
secondaryLabel: 'Can edit but not share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canView',
|
||||
value: 'can_view',
|
||||
label: 'Can view',
|
||||
secondaryLabel: 'Can view dashboard and metrics but not edit.'
|
||||
}
|
||||
|
@ -158,17 +168,17 @@ const dashboardItems: DropdownItem<ShareRole>[] = [
|
|||
|
||||
const collectionItems: DropdownItem<ShareRole>[] = [
|
||||
{
|
||||
value: 'fullAccess',
|
||||
value: 'full_access',
|
||||
label: 'Full access',
|
||||
secondaryLabel: 'Can edit and share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canEdit',
|
||||
value: 'can_edit',
|
||||
label: 'Can edit',
|
||||
secondaryLabel: 'Can edit but not share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canView',
|
||||
value: 'can_view',
|
||||
label: 'Can view',
|
||||
secondaryLabel: 'Can view assets but not edit.'
|
||||
}
|
||||
|
@ -176,17 +186,17 @@ const collectionItems: DropdownItem<ShareRole>[] = [
|
|||
|
||||
const reportItems: DropdownItem<ShareRole>[] = [
|
||||
{
|
||||
value: 'fullAccess',
|
||||
value: 'full_access',
|
||||
label: 'Full access',
|
||||
secondaryLabel: 'Can edit and share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canEdit',
|
||||
value: 'can_edit',
|
||||
label: 'Can edit',
|
||||
secondaryLabel: 'Can edit but not share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canView',
|
||||
value: 'can_view',
|
||||
label: 'Can view',
|
||||
secondaryLabel: 'Can view asset but not edit.'
|
||||
}
|
||||
|
@ -194,17 +204,17 @@ const reportItems: DropdownItem<ShareRole>[] = [
|
|||
|
||||
const workspaceItems: DropdownItem<WorkspaceShareRole>[] = [
|
||||
{
|
||||
value: 'fullAccess',
|
||||
value: 'full_access',
|
||||
label: 'Full access',
|
||||
secondaryLabel: 'Can edit and share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canEdit',
|
||||
value: 'can_edit',
|
||||
label: 'Can edit',
|
||||
secondaryLabel: 'Can edit, but not share with others.'
|
||||
},
|
||||
{
|
||||
value: 'canView',
|
||||
value: 'can_view',
|
||||
label: 'Can view',
|
||||
secondaryLabel: 'Cannot edit or share with others.'
|
||||
},
|
||||
|
|
|
@ -18,13 +18,13 @@ const mockShareConfig: ShareConfig = {
|
|||
individual_permissions: [
|
||||
{
|
||||
email: 'test_with_a_long_name_like_super_long_name@test.com',
|
||||
role: 'canView',
|
||||
role: 'can_view',
|
||||
name: 'Test User',
|
||||
avatar_url: null
|
||||
},
|
||||
{
|
||||
email: 'test2@test.com',
|
||||
role: 'fullAccess',
|
||||
role: 'full_access',
|
||||
name: 'Test User 2 with a long name like super long name',
|
||||
avatar_url: null
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ export const ViewerPermission: Story = {
|
|||
assetType: 'metric',
|
||||
shareAssetConfig: {
|
||||
...mockShareConfig,
|
||||
permission: 'canView'
|
||||
permission: 'can_view'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -124,7 +124,7 @@ const ShareMenuContentShare: React.FC<ShareMenuContentBodyProps> = React.memo(
|
|||
const payload: Parameters<typeof onUpdateMetricShare>[0] = {
|
||||
id: assetId,
|
||||
params: {
|
||||
workspace_sharing: role
|
||||
workspace_sharing: role || 'none'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import type { MetricListItem } from '@buster/server-shared/metrics';
|
|||
import type { VerificationStatus } from '@buster/server-shared/share';
|
||||
|
||||
const statusRecordText: Record<VerificationStatus, string> = {
|
||||
['verified']: 'Verified',
|
||||
['requested']: 'Requested',
|
||||
['inReview']: 'In review',
|
||||
['backlogged']: 'Backlogged',
|
||||
['notVerified']: 'Not verified',
|
||||
['notRequested']: 'Not requested'
|
||||
verified: 'Verified',
|
||||
requested: 'Requested',
|
||||
inReview: 'In review',
|
||||
backlogged: 'Backlogged',
|
||||
notVerified: 'Not verified',
|
||||
notRequested: 'Not requested'
|
||||
};
|
||||
|
||||
export const getTooltipText = (status: VerificationStatus) => {
|
||||
|
|
|
@ -5,17 +5,17 @@ export const getIsOwner = (role: ShareRole | null | undefined) => {
|
|||
};
|
||||
|
||||
export const getIsEffectiveOwner = (role: ShareRole | null | undefined) => {
|
||||
return role === 'fullAccess' || role === 'owner';
|
||||
return role === 'full_access' || role === 'owner';
|
||||
};
|
||||
|
||||
export const canEdit = (role: ShareRole | null | undefined) => {
|
||||
return role === 'canEdit' || role === 'fullAccess' || role === 'owner';
|
||||
return role === 'can_edit' || role === 'full_access' || role === 'owner';
|
||||
};
|
||||
|
||||
export const canShare = (role: ShareRole | null | undefined) => {
|
||||
return role === 'fullAccess' || role === 'owner';
|
||||
return role === 'full_access' || role === 'owner';
|
||||
};
|
||||
|
||||
export const canFilter = (role: ShareRole | null | undefined) => {
|
||||
return role === 'fullAccess' || role === 'owner' || role === 'canEdit';
|
||||
return role === 'full_access' || role === 'owner' || role === 'can_edit';
|
||||
};
|
||||
|
|
|
@ -1,21 +1,8 @@
|
|||
{
|
||||
"name": "@buster/server-shared",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"module": "src/index.ts",
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"prebuild": "tsx scripts/type-import-check.ts",
|
||||
"build": "tsc --build",
|
||||
"build:dry-run": "tsc --build",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "biome check --write",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run --exclude '**/*.int.test.ts' --exclude '**/*.integration.test.ts' --passWithNoTests",
|
||||
"test:integration": "vitest run **/*.int.test.ts **/*.integration.test.ts",
|
||||
"test:watch": "vitest"
|
||||
},
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
|
@ -82,16 +69,23 @@
|
|||
"default": "./dist/lib/report/index.js"
|
||||
}
|
||||
},
|
||||
"module": "src/index.ts",
|
||||
"scripts": {
|
||||
"prebuild": "tsx scripts/type-import-check.ts",
|
||||
"build": "tsc --build",
|
||||
"build:dry-run": "tsc --build",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "biome check --write",
|
||||
"test": "vitest run",
|
||||
"test:integration": "vitest run **/*.int.test.ts **/*.integration.test.ts",
|
||||
"test:unit": "vitest run --exclude '**/*.int.test.ts' --exclude '**/*.integration.test.ts' --passWithNoTests",
|
||||
"test:watch": "vitest",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@buster/database": "workspace:*",
|
||||
"@buster/typescript-config": "workspace:*",
|
||||
"@buster/vitest-config": "workspace:*",
|
||||
"@platejs/autoformat": "catalog:",
|
||||
"@platejs/basic-nodes": "catalog:",
|
||||
"@platejs/markdown": "catalog:",
|
||||
"platejs": "catalog:",
|
||||
"remark-gfm": "catalog:",
|
||||
"remark-math": "^6.0.0",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -53,8 +53,6 @@ export const BulkUpdateMetricVerificationStatusRequestSchema = z.array(
|
|||
})
|
||||
);
|
||||
|
||||
export const ShareDeleteRequestSchema = z.array(z.string());
|
||||
|
||||
export const ShareUpdateRequestSchema = z.object({
|
||||
users: z
|
||||
.array(
|
||||
|
@ -79,5 +77,3 @@ export type DuplicateMetricRequest = z.infer<typeof DuplicateMetricRequestSchema
|
|||
export type BulkUpdateMetricVerificationStatusRequest = z.infer<
|
||||
typeof BulkUpdateMetricVerificationStatusRequestSchema
|
||||
>;
|
||||
export type ShareDeleteRequest = z.infer<typeof ShareDeleteRequestSchema>;
|
||||
export type ShareUpdateRequest = z.infer<typeof ShareUpdateRequestSchema>;
|
||||
|
|
|
@ -2,3 +2,4 @@ export * from './reports.types';
|
|||
export * from './requests';
|
||||
export * from './responses';
|
||||
export * from './reports.types';
|
||||
export * from './report-elements';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { ReportElements } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
import { AssetCollectionsSchema } from '../collections/shared-asset-collections';
|
||||
import { IndividualPermissionsSchema } from '../shared-permissions';
|
||||
import { IndividualPermissionsSchema } from '../share';
|
||||
import { VersionsSchema } from '../version-shared';
|
||||
|
||||
export const ReportListItemSchema = z.object({
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { ReportElements } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
import { WorkspaceSharingSchema } from '../shared-permissions';
|
||||
import { PaginatedRequestSchema } from '../type-utilities/pagination';
|
||||
|
||||
export const GetReportsListRequestSchema = PaginatedRequestSchema;
|
||||
|
@ -15,12 +14,3 @@ export const UpdateReportRequestSchema = z
|
|||
|
||||
export type UpdateReportRequest = z.infer<typeof UpdateReportRequestSchema>;
|
||||
export type GetReportsListRequest = z.infer<typeof GetReportsListRequestSchema>;
|
||||
|
||||
export const ShareUpdateRequestSchema = z.object({
|
||||
publicly_accessible: z.boolean().optional(),
|
||||
public_expiry_date: z.string().optional(),
|
||||
public_password: z.string().optional(),
|
||||
workspace_sharing: WorkspaceSharingSchema.optional(),
|
||||
});
|
||||
|
||||
export type ShareUpdateRequest = z.infer<typeof ShareUpdateRequestSchema>;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import type { assetPermissionRoleEnum } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
|
||||
type AssetPermissionRoleBase = (typeof assetPermissionRoleEnum.enumValues)[number];
|
||||
const AssetPermissionRoleEnums: Record<AssetPermissionRoleBase, AssetPermissionRoleBase> =
|
||||
Object.freeze({
|
||||
owner: 'owner',
|
||||
viewer: 'viewer',
|
||||
full_access: 'full_access',
|
||||
can_edit: 'can_edit',
|
||||
can_filter: 'can_filter',
|
||||
can_view: 'can_view',
|
||||
});
|
||||
|
||||
export const AssetPermissionRoleSchema = z.enum(
|
||||
Object.values(AssetPermissionRoleEnums) as [AssetPermissionRoleBase, ...AssetPermissionRoleBase[]]
|
||||
);
|
|
@ -1,3 +1,5 @@
|
|||
export * from './share-interfaces.types';
|
||||
export * from './verification.types';
|
||||
export * from './requests';
|
||||
export * from './individual-permissions';
|
||||
export * from './assets';
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { z } from 'zod';
|
||||
import { AssetPermissionRoleSchema } from './assets';
|
||||
|
||||
export const IndividualPermissionSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string().nullable(),
|
||||
email: z.string(),
|
||||
avatar_url: z.string().nullable(),
|
||||
role: AssetPermissionRoleSchema,
|
||||
});
|
||||
|
||||
export type IndividualPermission = z.infer<typeof IndividualPermissionSchema>;
|
||||
|
||||
export const IndividualPermissionsSchema = z.array(IndividualPermissionSchema);
|
||||
|
||||
export type IndividualPermissions = z.infer<typeof IndividualPermissionsSchema>;
|
|
@ -1,5 +1,5 @@
|
|||
import { z } from 'zod';
|
||||
import { ShareRoleSchema } from './share-interfaces.types';
|
||||
import { ShareRoleSchema, WorkspaceShareRoleSchema } from './share-interfaces.types';
|
||||
|
||||
export const SharePostRequestSchema = z.array(
|
||||
z.object({
|
||||
|
@ -11,3 +11,26 @@ export const SharePostRequestSchema = z.array(
|
|||
);
|
||||
|
||||
export type SharePostRequest = z.infer<typeof SharePostRequestSchema>;
|
||||
|
||||
//Used for updating share permissions for a report, collection, or metric
|
||||
export const ShareUpdateRequestSchema = z.object({
|
||||
publicly_accessible: z.boolean().optional(),
|
||||
public_expiry_date: z.string().optional(),
|
||||
public_password: z.string().optional(),
|
||||
workspace_sharing: WorkspaceShareRoleSchema.optional(),
|
||||
users: z
|
||||
.array(
|
||||
z.object({
|
||||
email: z.string(),
|
||||
role: ShareRoleSchema,
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export type ShareUpdateRequest = z.infer<typeof ShareUpdateRequestSchema>;
|
||||
|
||||
//Used for deleting share permissions for a report, collection, or metric
|
||||
export const ShareDeleteRequestSchema = z.array(z.string());
|
||||
|
||||
export type ShareDeleteRequest = z.infer<typeof ShareDeleteRequestSchema>;
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
|
||||
describe('ShareRoleSchema', () => {
|
||||
it('should accept valid role values', () => {
|
||||
const validRoles = ['owner', 'fullAccess', 'canEdit', 'canView'];
|
||||
const validRoles = ['owner', 'full_access', 'can_edit', 'can_view'];
|
||||
|
||||
for (const role of validRoles) {
|
||||
const result = ShareRoleSchema.safeParse(role);
|
||||
|
@ -148,7 +148,7 @@ describe('ShareIndividualSchema', () => {
|
|||
});
|
||||
|
||||
it('should handle all valid role combinations', () => {
|
||||
const validRoles = ['owner', 'fullAccess', 'canEdit', 'canView'];
|
||||
const validRoles = ['owner', 'full_access', 'can_edit', 'can_view'];
|
||||
|
||||
for (const role of validRoles) {
|
||||
const individual = {
|
||||
|
@ -233,7 +233,7 @@ describe('ShareConfigSchema', () => {
|
|||
public_enabled_by: 'system',
|
||||
publicly_accessible: true,
|
||||
public_password: null,
|
||||
permission: 'fullAccess',
|
||||
permission: 'full_access',
|
||||
workspace_sharing: null,
|
||||
workspace_member_count: null,
|
||||
};
|
||||
|
@ -244,12 +244,12 @@ describe('ShareConfigSchema', () => {
|
|||
if (result.success) {
|
||||
expect(result.data.individual_permissions).toEqual([]);
|
||||
expect(result.data.publicly_accessible).toBe(true);
|
||||
expect(result.data.permission).toBe('fullAccess');
|
||||
expect(result.data.permission).toBe('full_access');
|
||||
}
|
||||
});
|
||||
|
||||
it('should validate all permission field values', () => {
|
||||
const validPermissions = ['owner', 'fullAccess', 'canEdit', 'canView'];
|
||||
const validPermissions = ['owner', 'full_access', 'can_edit', 'can_view'];
|
||||
|
||||
for (const permission of validPermissions) {
|
||||
const config = {
|
||||
|
@ -361,12 +361,12 @@ describe('ShareConfigSchema', () => {
|
|||
},
|
||||
{
|
||||
email: 'editor@company.com',
|
||||
role: 'canEdit',
|
||||
role: 'can_edit',
|
||||
name: 'Editor User',
|
||||
},
|
||||
{
|
||||
email: 'viewer@external.com',
|
||||
role: 'canView',
|
||||
role: 'can_view',
|
||||
// name is optional
|
||||
},
|
||||
],
|
||||
|
@ -374,7 +374,7 @@ describe('ShareConfigSchema', () => {
|
|||
public_enabled_by: 'admin@company.com',
|
||||
publicly_accessible: true,
|
||||
public_password: 'complex_password_123!',
|
||||
permission: 'fullAccess',
|
||||
permission: 'full_access',
|
||||
workspace_sharing: null,
|
||||
workspace_member_count: null,
|
||||
};
|
||||
|
@ -385,8 +385,8 @@ describe('ShareConfigSchema', () => {
|
|||
if (result.success) {
|
||||
expect(result.data.individual_permissions).toHaveLength(3);
|
||||
expect(result.data.individual_permissions?.[0]?.role).toBe('owner');
|
||||
expect(result.data.individual_permissions?.[1]?.role).toBe('canEdit');
|
||||
expect(result.data.individual_permissions?.[2]?.role).toBe('canView');
|
||||
expect(result.data.individual_permissions?.[1]?.role).toBe('can_edit');
|
||||
expect(result.data.individual_permissions?.[2]?.role).toBe('can_view');
|
||||
expect(result.data.individual_permissions?.[2]?.name).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,15 +1,37 @@
|
|||
import type { assetPermissionRoleEnum, workspaceSharingEnum } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
import { AssetTypeSchema } from '../assets/asset-types.types';
|
||||
|
||||
export const ShareRoleSchema = z.enum([
|
||||
'owner', //owner of the asset
|
||||
'fullAccess', //same as owner, can share with others
|
||||
'canEdit', //can edit, cannot share
|
||||
'canView', //can view asset
|
||||
]);
|
||||
type ShareRoleBase = (typeof assetPermissionRoleEnum.enumValues)[number];
|
||||
export const ShareRoleEnumsConversions: Record<ShareRoleBase, ShareRoleBase> = Object.freeze({
|
||||
owner: 'owner',
|
||||
full_access: 'full_access',
|
||||
can_edit: 'can_edit',
|
||||
can_view: 'can_view',
|
||||
viewer: 'viewer',
|
||||
can_filter: 'can_filter',
|
||||
});
|
||||
|
||||
export const WorkspaceShareRoleSchema = z.enum([...ShareRoleSchema.options, 'none']);
|
||||
export const ShareRoleSchema = z.enum(
|
||||
Object.values(ShareRoleEnumsConversions) as [ShareRoleBase, ...ShareRoleBase[]]
|
||||
);
|
||||
|
||||
//type TeamRoleBase = (typeof teamRoleEnum.enumValues)[number] | 'none';
|
||||
type WorkspaceShareRoleBase = (typeof workspaceSharingEnum.enumValues)[number];
|
||||
const WorkspaceShareRoleEnumsConversions: Record<WorkspaceShareRoleBase, WorkspaceShareRoleBase> =
|
||||
Object.freeze({
|
||||
full_access: 'full_access',
|
||||
can_edit: 'can_edit',
|
||||
can_view: 'can_view',
|
||||
none: 'none',
|
||||
});
|
||||
|
||||
export const WorkspaceShareRoleSchema = z.enum(
|
||||
Object.values(WorkspaceShareRoleEnumsConversions) as [
|
||||
WorkspaceShareRoleBase,
|
||||
...WorkspaceShareRoleBase[],
|
||||
]
|
||||
);
|
||||
export const ShareAssetTypeSchema = AssetTypeSchema;
|
||||
|
||||
export const ShareIndividualSchema = z.object({
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import type { verificationEnum } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const VerificationStatusSchema = z.enum([
|
||||
'notRequested',
|
||||
'requested',
|
||||
'inReview',
|
||||
'verified',
|
||||
'backlogged',
|
||||
'notVerified',
|
||||
]);
|
||||
type VerificationStatusBase = (typeof verificationEnum.enumValues)[number] | 'notVerified';
|
||||
const VerificationStatusEnums: Record<VerificationStatusBase, VerificationStatusBase> =
|
||||
Object.freeze({
|
||||
notRequested: 'notRequested',
|
||||
requested: 'requested',
|
||||
inReview: 'inReview',
|
||||
verified: 'verified',
|
||||
backlogged: 'backlogged',
|
||||
notVerified: 'notVerified',
|
||||
});
|
||||
|
||||
export const VerificationStatusSchema = z.enum(
|
||||
Object.values(VerificationStatusEnums) as [VerificationStatusBase, ...VerificationStatusBase[]]
|
||||
);
|
||||
|
||||
export type VerificationStatus = z.infer<typeof VerificationStatusSchema>;
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import type { assetPermissionRoleEnum, workspaceSharingEnum } from '@buster/database';
|
||||
import { z } from 'zod';
|
||||
|
||||
type AssetPermissionRoleBase = (typeof assetPermissionRoleEnum.enumValues)[number];
|
||||
const AssetPermissionRoleEnums: Record<AssetPermissionRoleBase, AssetPermissionRoleBase> =
|
||||
Object.freeze({
|
||||
owner: 'owner',
|
||||
viewer: 'viewer',
|
||||
full_access: 'full_access',
|
||||
can_edit: 'can_edit',
|
||||
can_filter: 'can_filter',
|
||||
can_view: 'can_view',
|
||||
});
|
||||
|
||||
export const AssetPermissionRoleSchema = z.enum(
|
||||
Object.values(AssetPermissionRoleEnums) as [AssetPermissionRoleBase, ...AssetPermissionRoleBase[]]
|
||||
);
|
||||
|
||||
export const IndividualPermissionSchema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string().nullable(),
|
||||
email: z.string(),
|
||||
avatar_url: z.string().nullable(),
|
||||
role: AssetPermissionRoleSchema,
|
||||
});
|
||||
|
||||
export type IndividualPermission = z.infer<typeof IndividualPermissionSchema>;
|
||||
|
||||
export const IndividualPermissionsSchema = z.array(IndividualPermissionSchema);
|
||||
|
||||
export type IndividualPermissions = z.infer<typeof IndividualPermissionsSchema>;
|
||||
|
||||
type WorkspaceSharingBase = (typeof workspaceSharingEnum.enumValues)[number];
|
||||
const WorkspaceSharingEnums: Record<WorkspaceSharingBase, WorkspaceSharingBase> = Object.freeze({
|
||||
none: 'none',
|
||||
can_view: 'can_view',
|
||||
can_edit: 'can_edit',
|
||||
full_access: 'full_access',
|
||||
});
|
||||
|
||||
export const WorkspaceSharingSchema = z.enum(
|
||||
Object.values(WorkspaceSharingEnums) as [WorkspaceSharingBase, ...WorkspaceSharingBase[]]
|
||||
);
|
|
@ -0,0 +1,38 @@
|
|||
# TypeScript build artifacts
|
||||
dist/
|
||||
build/
|
||||
*.tsbuildinfo
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Coverage
|
||||
coverage/
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# Node modules
|
||||
node_modules/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
.DS_Store
|
||||
|
||||
# Environment files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Test artifacts
|
||||
junit.xml
|
||||
test-results/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
|
@ -0,0 +1,7 @@
|
|||
# @buster/server-utils
|
||||
|
||||
Server utilities for Buster that can be used in any server-side application across the monorepo.
|
||||
|
||||
## Overview
|
||||
|
||||
This package provides common server-side utilities and helper functions that are shared across different backend applications in the Buster ecosystem. It centralizes reusable server logic to avoid code duplication and ensure consistency across services.
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"extends": ["../../biome.json"],
|
||||
"files": {
|
||||
"include": ["src/**/*", "scripts/**/*"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NODE_ENV?: 'development' | 'production' | 'test';
|
||||
// Add your environment variables here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"name": "@buster/server-utils",
|
||||
"description": "Server utilities for Buster that can be used in any server-side application",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
"./report": {
|
||||
"types": "./dist/report/index.d.ts",
|
||||
"default": "./dist/report/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts",
|
||||
"build": "tsc",
|
||||
"build:dry-run": "tsc",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "biome check --write",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run --exclude '**/*.int.test.ts' --exclude '**/*.integration.test.ts' --passWithNoTests",
|
||||
"test:integration": "vitest run **/*.int.test.ts **/*.integration.test.ts",
|
||||
"test:watch": "vitest watch",
|
||||
"test:coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@buster/typescript-config": "workspace:*",
|
||||
"@buster/vitest-config": "workspace:*",
|
||||
"@buster/env-utils": "workspace:*",
|
||||
"@buster/database": "workspace:*",
|
||||
"zod": "catalog:",
|
||||
"@platejs/autoformat": "catalog:",
|
||||
"@platejs/basic-nodes": "catalog:",
|
||||
"@platejs/markdown": "catalog:",
|
||||
"platejs": "catalog:",
|
||||
"remark-gfm": "catalog:",
|
||||
"remark-math": "^6.0.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// This script uses the shared env-utils to validate environment variables
|
||||
import { loadRootEnv, validateEnv } from '@buster/env-utils';
|
||||
|
||||
// Load environment variables from root .env file
|
||||
loadRootEnv();
|
||||
|
||||
// Define required environment variables for this package
|
||||
const requiredEnv = {
|
||||
// NODE_ENV is optional - will default to 'development' if not set
|
||||
// Add your required environment variables here:
|
||||
// DATABASE_URL: process.env.DATABASE_URL,
|
||||
// API_KEY: process.env.API_KEY,
|
||||
};
|
||||
|
||||
// Validate environment variables
|
||||
const { hasErrors } = validateEnv(requiredEnv);
|
||||
|
||||
if (hasErrors) {
|
||||
process.exit(1);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"extends": "@buster/typescript-config/base.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "dist/.cache/tsbuildinfo.json",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"include": ["src/**/*", "env.d.ts"],
|
||||
"exclude": ["node_modules", "dist", "tests", "**/*.test.ts", "**/*.spec.ts"]
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { baseConfig } from '@buster/vitest-config';
|
||||
|
||||
export default baseConfig;
|
|
@ -1043,6 +1043,31 @@ importers:
|
|||
'@buster/vitest-config':
|
||||
specifier: workspace:*
|
||||
version: link:../vitest-config
|
||||
zod:
|
||||
specifier: 'catalog:'
|
||||
version: 3.25.1
|
||||
devDependencies:
|
||||
tsx:
|
||||
specifier: 'catalog:'
|
||||
version: 4.20.3
|
||||
vitest:
|
||||
specifier: 'catalog:'
|
||||
version: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@24.0.10)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||
|
||||
packages/server-utils:
|
||||
dependencies:
|
||||
'@buster/database':
|
||||
specifier: workspace:*
|
||||
version: link:../database
|
||||
'@buster/env-utils':
|
||||
specifier: workspace:*
|
||||
version: link:../env-utils
|
||||
'@buster/typescript-config':
|
||||
specifier: workspace:*
|
||||
version: link:../typescript-config
|
||||
'@buster/vitest-config':
|
||||
specifier: workspace:*
|
||||
version: link:../vitest-config
|
||||
'@platejs/autoformat':
|
||||
specifier: 'catalog:'
|
||||
version: 49.0.0(platejs@49.2.4(@types/react@18.3.23)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(scheduler@0.23.2)(slate-dom@0.116.0(slate@0.117.0))(slate@0.117.0)(use-sync-external-store@1.5.0(react@18.3.1)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
@ -1064,13 +1089,6 @@ importers:
|
|||
zod:
|
||||
specifier: 'catalog:'
|
||||
version: 3.25.1
|
||||
devDependencies:
|
||||
tsx:
|
||||
specifier: 'catalog:'
|
||||
version: 4.20.3
|
||||
vitest:
|
||||
specifier: 'catalog:'
|
||||
version: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@24.0.10)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||
|
||||
packages/slack:
|
||||
dependencies:
|
||||
|
@ -6783,7 +6801,6 @@ packages:
|
|||
|
||||
bun@1.2.18:
|
||||
resolution: {integrity: sha512-OR+EpNckoJN4tHMVZPaTPxDj2RgpJgJwLruTIFYbO3bQMguLd0YrmkWKYqsiihcLgm2ehIjF/H1RLfZiRa7+qQ==}
|
||||
cpu: [arm64, x64, aarch64]
|
||||
os: [darwin, linux, win32]
|
||||
hasBin: true
|
||||
|
||||
|
@ -19222,14 +19239,14 @@ snapshots:
|
|||
msw: 2.10.4(@types/node@20.19.4)(typescript@5.8.3)
|
||||
vite: 6.3.5(@types/node@20.19.4)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||
|
||||
'@vitest/mocker@3.2.4(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
|
||||
'@vitest/mocker@3.2.4(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(vite@6.3.5(@types/node@20.19.4)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.17
|
||||
optionalDependencies:
|
||||
msw: 2.10.4(@types/node@24.0.10)(typescript@5.8.3)
|
||||
vite: 6.3.5(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||
vite: 6.3.5(@types/node@20.19.4)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||
|
||||
'@vitest/pretty-format@2.0.5':
|
||||
dependencies:
|
||||
|
@ -26558,7 +26575,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/chai': 5.2.2
|
||||
'@vitest/expect': 3.2.4
|
||||
'@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(vite@6.3.5(@types/node@24.0.10)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
|
||||
'@vitest/mocker': 3.2.4(msw@2.10.4(@types/node@24.0.10)(typescript@5.8.3))(vite@6.3.5(@types/node@20.19.4)(jiti@2.4.2)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0))
|
||||
'@vitest/pretty-format': 3.2.4
|
||||
'@vitest/runner': 3.2.4
|
||||
'@vitest/snapshot': 3.2.4
|
||||
|
|
Loading…
Reference in New Issue