Drop `position` from the `asset_usages` unique constraint so the same asset can't be attached to one target/slot more than once, and update the insert's onConflict target + lookup to match the narrower key. Guard it at the service layer too: attachAssetService now rejects an attach when the asset already has a usage for that target with a new ASSET_ALREADY_ATTACHED (409) error, backed by an assetUsageExistsForTarget query.
186 lines
7.5 KiB
TypeScript
186 lines
7.5 KiB
TypeScript
/**
|
|
* Wire `code` values returned in API JSON error bodies (`success: false`).
|
|
* Shared by `@cio/api` and clients (e.g. dashboard snackbar mapping).
|
|
*/
|
|
export const ErrorCodes = {
|
|
// Common errors
|
|
NOT_FOUND: 'NOT_FOUND',
|
|
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
|
|
// Dashboard Analytics errors
|
|
ORG_ANALYTICS_FETCH_FAILED: 'ORG_ANALYTICS_FETCH_FAILED',
|
|
NO_ORG_ID_PROVIDED: 'NO_ORG_ID_PROVIDED',
|
|
|
|
// Community errors
|
|
UPDATE_COMMUNITY_QUESTION_FAILED: 'UPDATE_COMMUNITY_QUESTION_FAILED',
|
|
ADD_COMMUNITY_QUESTION_FAILED: 'ADD_COMMUNITY_QUESTION_FAILED',
|
|
COMMUNITY_QUESTIONS_FETCH_FAILED: 'COMMUNITY_QUESTIONS_FETCH_FAILED',
|
|
COMMUNITY_QUESTION_NOT_FOUND: 'COMMUNITY_QUESTION_NOT_FOUND',
|
|
COMMENT_SUBMISSION_FAILED: 'COMMENT_SUBMISSION_FAILED',
|
|
UPVOTE_FAILED: 'UPVOTE_FAILED',
|
|
DELETE_COMMENT_FAILED: 'DELETE_COMMENT_FAILED',
|
|
DELETE_QUESTION_FAILED: 'DELETE_QUESTION_FAILED',
|
|
|
|
// Organization errors
|
|
SITENAME_EXISTS: 'SITENAME_EXISTS',
|
|
ORG_CREATE_FAILED: 'ORG_CREATE_FAILED',
|
|
ORG_NOT_FOUND: 'ORG_NOT_FOUND',
|
|
ORGANIZATION_NOT_FOUND: 'ORGANIZATION_NOT_FOUND',
|
|
ORG_TEAM_FETCH_FAILED: 'ORG_TEAM_FETCH_FAILED',
|
|
ORG_AUDIENCE_FETCH_FAILED: 'ORG_AUDIENCE_FETCH_FAILED',
|
|
COURSES_FETCH_FAILED: 'COURSES_FETCH_FAILED',
|
|
ORG_PLAN_CREATE_FAILED: 'ORG_PLAN_CREATE_FAILED',
|
|
ORG_PLAN_UPDATE_FAILED: 'ORG_PLAN_UPDATE_FAILED',
|
|
ORG_PLAN_CANCEL_FAILED: 'ORG_PLAN_CANCEL_FAILED',
|
|
ORG_PLAN_NOT_FOUND: 'ORG_PLAN_NOT_FOUND',
|
|
ORG_TEAM_INVITE_FAILED: 'ORG_TEAM_INVITE_FAILED',
|
|
ORG_TEAM_REMOVE_FAILED: 'ORG_TEAM_REMOVE_FAILED',
|
|
ORG_AUDIENCE_REMOVE_FAILED: 'ORG_AUDIENCE_REMOVE_FAILED',
|
|
ORG_TEAM_EMAIL_EXISTS: 'ORG_TEAM_EMAIL_EXISTS',
|
|
ORG_TEAM_NOT_AUTHORIZED: 'ORG_TEAM_NOT_AUTHORIZED',
|
|
ORGANIZATION_API_KEY_NOT_FOUND: 'ORGANIZATION_API_KEY_NOT_FOUND',
|
|
ORGANIZATION_API_KEY_CREATE_FAILED: 'ORGANIZATION_API_KEY_CREATE_FAILED',
|
|
ORGANIZATION_API_KEY_FETCH_FAILED: 'ORGANIZATION_API_KEY_FETCH_FAILED',
|
|
ORGANIZATION_API_KEY_REVOKE_FAILED: 'ORGANIZATION_API_KEY_REVOKE_FAILED',
|
|
ORGANIZATION_API_KEY_ROTATE_FAILED: 'ORGANIZATION_API_KEY_ROTATE_FAILED',
|
|
AUTOMATION_KEY_LIMIT_EXCEEDED: 'AUTOMATION_KEY_LIMIT_EXCEEDED',
|
|
AUTOMATION_CREDIT_LIMIT_EXCEEDED: 'AUTOMATION_CREDIT_LIMIT_EXCEEDED',
|
|
AUTOMATION_RATE_LIMIT_EXCEEDED: 'AUTOMATION_RATE_LIMIT_EXCEEDED',
|
|
TAG_GROUP_NOT_FOUND: 'TAG_GROUP_NOT_FOUND',
|
|
TAG_NOT_FOUND: 'TAG_NOT_FOUND',
|
|
TAG_FETCH_FAILED: 'TAG_FETCH_FAILED',
|
|
TAG_CREATE_FAILED: 'TAG_CREATE_FAILED',
|
|
TAG_UPDATE_FAILED: 'TAG_UPDATE_FAILED',
|
|
TAG_ASSIGNMENT_FAILED: 'TAG_ASSIGNMENT_FAILED',
|
|
WIDGET_NOT_FOUND: 'WIDGET_NOT_FOUND',
|
|
WIDGET_FETCH_FAILED: 'WIDGET_FETCH_FAILED',
|
|
WIDGET_CREATE_FAILED: 'WIDGET_CREATE_FAILED',
|
|
WIDGET_UPDATE_FAILED: 'WIDGET_UPDATE_FAILED',
|
|
WIDGET_DELETE_FAILED: 'WIDGET_DELETE_FAILED',
|
|
WIDGET_PUBLISH_FAILED: 'WIDGET_PUBLISH_FAILED',
|
|
WIDGET_ROLLBACK_FAILED: 'WIDGET_ROLLBACK_FAILED',
|
|
WIDGET_PAYLOAD_FETCH_FAILED: 'WIDGET_PAYLOAD_FETCH_FAILED',
|
|
|
|
// Asset errors
|
|
ASSET_NOT_FOUND: 'ASSET_NOT_FOUND',
|
|
ASSET_IN_USE: 'ASSET_IN_USE',
|
|
ASSET_USAGE_NOT_FOUND: 'ASSET_USAGE_NOT_FOUND',
|
|
ASSET_CREATE_FAILED: 'ASSET_CREATE_FAILED',
|
|
ASSET_FETCH_FAILED: 'ASSET_FETCH_FAILED',
|
|
ASSET_LIST_FAILED: 'ASSET_LIST_FAILED',
|
|
ASSET_UPDATE_FAILED: 'ASSET_UPDATE_FAILED',
|
|
ASSET_DELETE_FAILED: 'ASSET_DELETE_FAILED',
|
|
ASSET_ATTACH_FAILED: 'ASSET_ATTACH_FAILED',
|
|
ASSET_ALREADY_ATTACHED: 'ASSET_ALREADY_ATTACHED',
|
|
ASSET_DETACH_FAILED: 'ASSET_DETACH_FAILED',
|
|
ASSET_USAGE_FETCH_FAILED: 'ASSET_USAGE_FETCH_FAILED',
|
|
ASSET_EXPORT_FAILED: 'ASSET_EXPORT_FAILED',
|
|
ASSET_STORAGE_FETCH_FAILED: 'ASSET_STORAGE_FETCH_FAILED',
|
|
ASSET_NOT_TRANSCRIBABLE: 'ASSET_NOT_TRANSCRIBABLE',
|
|
|
|
OPENAI_KEY_MISSING: 'OPENAI_KEY_MISSING',
|
|
|
|
// Profile errors
|
|
PROFILE_UPDATE_FAILED: 'PROFILE_UPDATE_FAILED',
|
|
PROFILE_NOT_FOUND: 'PROFILE_NOT_FOUND',
|
|
|
|
// Account errors
|
|
ACCOUNT_NOT_FOUND: 'ACCOUNT_NOT_FOUND',
|
|
WORKSPACE_NOT_FOUND: 'WORKSPACE_NOT_FOUND',
|
|
WORKSPACE_LIMIT_REACHED: 'WORKSPACE_LIMIT_REACHED',
|
|
WORKSPACE_READ_ONLY: 'WORKSPACE_READ_ONLY',
|
|
WORKSPACE_IS_PRIMARY: 'WORKSPACE_IS_PRIMARY',
|
|
PLAN_UPGRADE_REQUIRED: 'PLAN_UPGRADE_REQUIRED',
|
|
NOT_PRIMARY_WORKSPACE: 'NOT_PRIMARY_WORKSPACE',
|
|
|
|
// Auth errors
|
|
FORBIDDEN: 'FORBIDDEN',
|
|
|
|
// Course errors
|
|
COURSE_NOT_FOUND: 'COURSE_NOT_FOUND',
|
|
COURSE_FETCH_FAILED: 'COURSE_FETCH_FAILED',
|
|
COURSE_IMPORT_DRAFT_NOT_FOUND: 'COURSE_IMPORT_DRAFT_NOT_FOUND',
|
|
COURSE_IMPORT_CREATE_FAILED: 'COURSE_IMPORT_CREATE_FAILED',
|
|
COURSE_IMPORT_FETCH_FAILED: 'COURSE_IMPORT_FETCH_FAILED',
|
|
COURSE_IMPORT_UPDATE_FAILED: 'COURSE_IMPORT_UPDATE_FAILED',
|
|
COURSE_IMPORT_PUBLISH_FAILED: 'COURSE_IMPORT_PUBLISH_FAILED',
|
|
SLUG_IN_USE: 'SLUG_IN_USE',
|
|
QUESTION_TYPE_NOT_ALLOWED_IN_PUBLIC_COURSE: 'QUESTION_TYPE_NOT_ALLOWED_IN_PUBLIC_COURSE',
|
|
PUBLIC_COURSE_CONVERSION_BLOCKED: 'PUBLIC_COURSE_CONVERSION_BLOCKED',
|
|
|
|
// Lesson errors
|
|
LESSON_NOT_FOUND: 'LESSON_NOT_FOUND',
|
|
LESSON_FETCH_FAILED: 'LESSON_FETCH_FAILED',
|
|
COURSE_SECTION_NOT_FOUND: 'COURSE_SECTION_NOT_FOUND',
|
|
|
|
// Exercise errors
|
|
EXERCISE_NOT_FOUND: 'EXERCISE_NOT_FOUND',
|
|
EXERCISE_FETCH_FAILED: 'EXERCISE_FETCH_FAILED',
|
|
|
|
// Submission errors
|
|
SUBMISSION_NOT_FOUND: 'SUBMISSION_NOT_FOUND',
|
|
SUBMISSION_FETCH_FAILED: 'SUBMISSION_FETCH_FAILED',
|
|
|
|
// Comment errors
|
|
COMMENT_NOT_FOUND: 'COMMENT_NOT_FOUND',
|
|
LESSON_COMMENT_UPDATE_FAILED: 'LESSON_COMMENT_UPDATE_FAILED',
|
|
NEWSFEED_COMMENT_UPDATE_FAILED: 'NEWSFEED_COMMENT_UPDATE_FAILED',
|
|
|
|
// Quiz errors
|
|
QUIZ_NOT_FOUND: 'QUIZ_NOT_FOUND',
|
|
QUIZ_FETCH_FAILED: 'QUIZ_FETCH_FAILED',
|
|
QUIZ_CREATE_FAILED: 'QUIZ_CREATE_FAILED',
|
|
QUIZ_UPDATE_FAILED: 'QUIZ_UPDATE_FAILED',
|
|
QUIZ_DELETE_FAILED: 'QUIZ_DELETE_FAILED',
|
|
|
|
// Lesson Language errors
|
|
LESSON_LANGUAGE_NOT_FOUND: 'LESSON_LANGUAGE_NOT_FOUND',
|
|
LESSON_LANGUAGE_FETCH_FAILED: 'LESSON_LANGUAGE_FETCH_FAILED',
|
|
LESSON_LANGUAGE_CREATE_FAILED: 'LESSON_LANGUAGE_CREATE_FAILED',
|
|
LESSON_LANGUAGE_UPDATE_FAILED: 'LESSON_LANGUAGE_UPDATE_FAILED',
|
|
LESSON_LANGUAGE_DELETE_FAILED: 'LESSON_LANGUAGE_DELETE_FAILED',
|
|
|
|
// SSO errors
|
|
SSO_REGISTRATION_FAILED: 'SSO_REGISTRATION_FAILED',
|
|
SSO_NOT_FOUND: 'SSO_NOT_FOUND',
|
|
SSO_NOT_ENABLED: 'SSO_NOT_ENABLED',
|
|
SOCIAL_AUTH_NOT_ENABLED: 'SOCIAL_AUTH_NOT_ENABLED',
|
|
UPGRADE_REQUIRED: 'UPGRADE_REQUIRED',
|
|
CONFLICT: 'CONFLICT',
|
|
|
|
// Token exchange errors
|
|
TOKEN_EXCHANGE_INVALID_TOKEN: 'TOKEN_EXCHANGE_INVALID_TOKEN',
|
|
TOKEN_EXCHANGE_EXPIRED: 'TOKEN_EXCHANGE_EXPIRED',
|
|
TOKEN_EXCHANGE_ORG_NOT_FOUND: 'TOKEN_EXCHANGE_ORG_NOT_FOUND',
|
|
TOKEN_EXCHANGE_NOT_ENABLED: 'TOKEN_EXCHANGE_NOT_ENABLED',
|
|
|
|
// Token auth admin errors
|
|
TOKEN_AUTH_ALREADY_EXISTS: 'TOKEN_AUTH_ALREADY_EXISTS',
|
|
|
|
// Program errors
|
|
PROGRAM_NOT_FOUND: 'PROGRAM_NOT_FOUND',
|
|
PROGRAM_FORBIDDEN: 'PROGRAM_FORBIDDEN',
|
|
PROGRAM_CREATE_FAILED: 'PROGRAM_CREATE_FAILED',
|
|
PROGRAM_UPDATE_FAILED: 'PROGRAM_UPDATE_FAILED',
|
|
PROGRAM_DELETE_FAILED: 'PROGRAM_DELETE_FAILED',
|
|
COURSE_ALREADY_IN_PROGRAM: 'COURSE_ALREADY_IN_PROGRAM',
|
|
MEMBER_ALREADY_IN_PROGRAM: 'MEMBER_ALREADY_IN_PROGRAM',
|
|
PROGRAM_MEMBER_NOT_FOUND: 'PROGRAM_MEMBER_NOT_FOUND',
|
|
PROGRAM_NEWSFEED_NOT_FOUND: 'PROGRAM_NEWSFEED_NOT_FOUND',
|
|
PROGRAM_NEWSFEED_COMMENT_NOT_FOUND: 'PROGRAM_NEWSFEED_COMMENT_NOT_FOUND',
|
|
PROGRAM_MEMBER_CHECK_FAILED: 'PROGRAM_MEMBER_CHECK_FAILED',
|
|
PROGRAM_GOAL_NOT_FOUND: 'PROGRAM_GOAL_NOT_FOUND',
|
|
PROGRAM_GOAL_CREATE_FAILED: 'PROGRAM_GOAL_CREATE_FAILED',
|
|
PROGRAM_GOAL_UPDATE_FAILED: 'PROGRAM_GOAL_UPDATE_FAILED',
|
|
PROGRAM_GOAL_DELETE_FAILED: 'PROGRAM_GOAL_DELETE_FAILED',
|
|
|
|
// AI assistant chat
|
|
NO_MESSAGES_TO_COMPACT: 'NO_MESSAGES_TO_COMPACT',
|
|
|
|
// Generic
|
|
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
INTERNAL_ERROR: 'INTERNAL_ERROR'
|
|
} as const;
|
|
|
|
export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|