insforge 1.2.10 → 1.3.0
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/.claude-plugin/marketplace.json +20 -20
- package/.dockerignore +60 -60
- package/.env.example +83 -77
- package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -36
- package/.github/ISSUE_TEMPLATE/config.yml +11 -11
- package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -26
- package/.github/PULL_REQUEST_TEMPLATE.md +7 -7
- package/.github/copilot-instructions.md +146 -146
- package/.github/workflows/build-image.yml +65 -65
- package/.github/workflows/ci-premerge-check.yml +23 -23
- package/.github/workflows/e2e.yml +63 -63
- package/.github/workflows/lint-and-format.yml +32 -32
- package/.prettierignore +64 -64
- package/CHANGELOG.md +44 -44
- package/CLAUDE_PLUGIN.md +104 -104
- package/CODE_OF_CONDUCT.md +128 -128
- package/CONTRIBUTING.md +125 -125
- package/Dockerfile +30 -30
- package/GITHUB_OAUTH_SETUP.md +49 -49
- package/GOOGLE_OAUTH_SETUP.md +148 -148
- package/LICENSE +201 -201
- package/README.md +182 -182
- package/assets/Dark.svg +23 -23
- package/auth/package.json +28 -28
- package/auth/src/lib/broadcastService.ts +117 -115
- package/auth/src/pages/SignInPage.tsx +60 -57
- package/auth/src/pages/SignUpPage.tsx +60 -57
- package/auth/tsconfig.json +32 -32
- package/auth/tsconfig.node.json +11 -11
- package/backend/package.json +78 -75
- package/backend/src/api/routes/ai/index.routes.ts +3 -3
- package/backend/src/api/routes/auth/index.routes.ts +667 -570
- package/backend/src/api/routes/auth/oauth.routes.ts +473 -448
- package/backend/src/api/routes/database/advance.routes.ts +37 -16
- package/backend/src/api/routes/database/index.routes.ts +78 -1
- package/backend/src/api/routes/database/records.routes.ts +10 -10
- package/backend/src/api/routes/database/tables.routes.ts +0 -14
- package/backend/src/api/routes/docs/index.routes.ts +75 -76
- package/backend/src/api/routes/email/index.routes.ts +35 -0
- package/backend/src/api/routes/functions/index.routes.ts +18 -12
- package/backend/src/api/routes/metadata/index.routes.ts +12 -0
- package/backend/src/api/routes/realtime/channels.routes.ts +81 -0
- package/backend/src/api/routes/realtime/index.routes.ts +12 -0
- package/backend/src/api/routes/realtime/messages.routes.ts +48 -0
- package/backend/src/api/routes/realtime/permissions.routes.ts +19 -0
- package/backend/src/api/routes/storage/index.routes.ts +18 -12
- package/backend/src/api/routes/usage/index.routes.ts +6 -4
- package/backend/src/infra/database/database.manager.ts +14 -1
- package/backend/src/infra/database/migrations/000_create-base-tables.sql +141 -141
- package/backend/src/infra/database/migrations/001_create-helper-functions.sql +40 -40
- package/backend/src/infra/database/migrations/002_rename-auth-tables.sql +29 -29
- package/backend/src/infra/database/migrations/003_create-users-table.sql +55 -55
- package/backend/src/infra/database/migrations/004_add-reload-postgrest-func.sql +23 -23
- package/backend/src/infra/database/migrations/005_enable-project-admin-modify-users.sql +29 -29
- package/backend/src/infra/database/migrations/006_modify-ai-usage-table.sql +24 -24
- package/backend/src/infra/database/migrations/007_drop-metadata-table.sql +1 -1
- package/backend/src/infra/database/migrations/008_add-system-tables.sql +76 -76
- package/backend/src/infra/database/migrations/009_add-function-secrets.sql +23 -23
- package/backend/src/infra/database/migrations/010_modify-ai-config-modalities.sql +93 -93
- package/backend/src/infra/database/migrations/011_refactor-secrets-table.sql +15 -15
- package/backend/src/infra/database/migrations/012_add-storage-uploaded-by.sql +7 -7
- package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -44
- package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +7 -7
- package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +59 -59
- package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -24
- package/backend/src/infra/database/migrations/017_create-realtime-schema.sql +233 -0
- package/backend/src/infra/realtime/realtime.manager.ts +246 -0
- package/backend/src/infra/realtime/webhook-sender.ts +82 -0
- package/backend/src/infra/security/token.manager.ts +219 -125
- package/backend/src/infra/socket/socket.manager.ts +198 -64
- package/backend/src/providers/ai/openrouter.provider.ts +12 -9
- package/backend/src/providers/email/base.provider.ts +4 -7
- package/backend/src/providers/email/cloud.provider.ts +84 -0
- package/backend/src/providers/oauth/apple.provider.ts +266 -0
- package/backend/src/providers/oauth/index.ts +1 -0
- package/backend/src/server.ts +317 -284
- package/backend/src/services/ai/ai-model.service.ts +5 -5
- package/backend/src/services/ai/chat-completion.service.ts +4 -4
- package/backend/src/services/ai/image-generation.service.ts +3 -3
- package/backend/src/services/auth/auth.service.ts +14 -0
- package/backend/src/services/database/database-table.service.ts +0 -9
- package/backend/src/services/database/database.service.ts +127 -0
- package/backend/src/services/email/email.service.ts +5 -7
- package/backend/src/services/realtime/index.ts +3 -0
- package/backend/src/services/realtime/realtime-auth.service.ts +104 -0
- package/backend/src/services/realtime/realtime-channel.service.ts +237 -0
- package/backend/src/services/realtime/realtime-message.service.ts +260 -0
- package/backend/src/types/auth.ts +11 -0
- package/backend/src/types/realtime.ts +18 -0
- package/backend/src/types/socket.ts +7 -31
- package/backend/src/utils/cookies.ts +35 -0
- package/backend/src/utils/s3-config-loader.ts +64 -0
- package/backend/src/utils/seed.ts +301 -298
- package/backend/src/utils/sql-parser.ts +90 -0
- package/backend/tests/README.md +133 -133
- package/backend/tests/cleanup-all-test-data.sh +230 -230
- package/backend/tests/cloud/test-s3-multitenant.sh +131 -131
- package/backend/tests/local/comprehensive-curl-tests.sh +155 -155
- package/backend/tests/local/test-ai-config.sh +129 -129
- package/backend/tests/local/test-ai-usage.sh +80 -80
- package/backend/tests/local/test-auth-router.sh +143 -143
- package/backend/tests/local/test-database-router.sh +222 -222
- package/backend/tests/local/test-e2e.sh +240 -240
- package/backend/tests/local/test-fk-errors.sh +96 -96
- package/backend/tests/local/test-functions.sh +123 -123
- package/backend/tests/local/test-id-field.sh +200 -200
- package/backend/tests/local/test-logs.sh +132 -132
- package/backend/tests/local/test-public-bucket.sh +264 -264
- package/backend/tests/local/test-secrets.sh +249 -249
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -325
- package/backend/tests/local/test-traditional-rest.sh +208 -208
- package/backend/tests/manual/README.md +50 -50
- package/backend/tests/manual/create-large-table-simple.sql +10 -10
- package/backend/tests/manual/seed-large-table.sql +100 -100
- package/backend/tests/manual/setup-large-table-extras.sql +33 -33
- package/backend/tests/manual/test-bulk-upsert.sh +409 -409
- package/backend/tests/manual/test-database-advance.sh +296 -296
- package/backend/tests/manual/test-postgrest-stability.sh +191 -191
- package/backend/tests/manual/test-rawsql-export-import.sh +411 -411
- package/backend/tests/manual/test-rawsql-modes.sh +244 -244
- package/backend/tests/manual/test-universal-storage.sh +263 -263
- package/backend/tests/manual/test-users.sql +17 -17
- package/backend/tests/run-all-tests.sh +139 -139
- package/backend/tests/setup.ts +0 -0
- package/backend/tests/test-config.sh +338 -338
- package/backend/tests/unit/analyze-query.test.ts +697 -0
- package/backend/tsconfig.json +22 -22
- package/claude-plugin/.claude-plugin/plugin.json +24 -24
- package/claude-plugin/README.md +133 -133
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -270
- package/docker-compose.prod.yml +204 -200
- package/docker-compose.yml +232 -228
- package/docker-init/db/db-init.sql +97 -97
- package/docker-init/db/jwt.sql +5 -5
- package/docker-init/db/postgresql.conf +16 -16
- package/docker-init/logs/vector.yml +236 -236
- package/docs/README.md +44 -44
- package/docs/agent-docs/real-time.md +269 -0
- package/docs/changelog.mdx +119 -67
- package/docs/core-concepts/ai/architecture.mdx +372 -372
- package/docs/core-concepts/ai/sdk.mdx +213 -213
- package/docs/core-concepts/authentication/architecture.mdx +278 -278
- package/docs/core-concepts/authentication/sdk.mdx +414 -414
- package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -529
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -221
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -184
- package/docs/core-concepts/authentication/ui-components/react.mdx +129 -129
- package/docs/core-concepts/database/architecture.mdx +255 -255
- package/docs/core-concepts/database/sdk.mdx +382 -382
- package/docs/core-concepts/email/architecture.mdx +101 -0
- package/docs/core-concepts/email/sdk.mdx +53 -0
- package/docs/core-concepts/functions/architecture.mdx +105 -105
- package/docs/core-concepts/functions/sdk.mdx +184 -184
- package/docs/core-concepts/realtime/architecture.mdx +446 -0
- package/docs/core-concepts/realtime/sdk.mdx +409 -0
- package/docs/core-concepts/storage/architecture.mdx +243 -243
- package/docs/core-concepts/storage/sdk.mdx +253 -253
- package/docs/deployment/README.md +94 -94
- package/docs/deployment/deploy-to-aws-ec2.md +564 -564
- package/docs/deployment/deploy-to-azure-virtual-machines.md +312 -312
- package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -613
- package/docs/deployment/deploy-to-render.md +441 -441
- package/docs/deprecated/insforge-auth-api.md +214 -214
- package/docs/deprecated/insforge-auth-sdk.md +99 -99
- package/docs/deprecated/insforge-db-api.md +358 -358
- package/docs/deprecated/insforge-db-sdk.md +139 -139
- package/docs/deprecated/insforge-debug-sdk.md +156 -156
- package/docs/deprecated/insforge-debug.md +64 -64
- package/docs/deprecated/insforge-instructions.md +123 -123
- package/docs/deprecated/insforge-project.md +117 -117
- package/docs/deprecated/insforge-storage-api.md +278 -278
- package/docs/deprecated/insforge-storage-sdk.md +158 -158
- package/docs/docs.json +232 -210
- package/docs/examples/framework-guides/nextjs.mdx +131 -131
- package/docs/examples/framework-guides/nuxt.mdx +165 -165
- package/docs/examples/framework-guides/react.mdx +165 -165
- package/docs/examples/framework-guides/svelte.mdx +153 -153
- package/docs/examples/framework-guides/vue.mdx +159 -159
- package/docs/examples/overview.mdx +67 -67
- package/docs/favicon.svg +19 -19
- package/docs/images/changelog/dec-2025/ai-integration.png +0 -0
- package/docs/images/changelog/dec-2025/ai-models.webp +0 -0
- package/docs/images/changelog/dec-2025/alipay-payment.webp +0 -0
- package/docs/images/changelog/dec-2025/apple-login.jpg +0 -0
- package/docs/images/changelog/dec-2025/mcp-installer.png +0 -0
- package/docs/images/changelog/dec-2025/realtime-module.jpg +0 -0
- package/docs/images/icons/ai.svg +4 -4
- package/docs/images/logos/nextjs.svg +4 -4
- package/docs/images/logos/nuxt.svg +4 -4
- package/docs/images/logos/react.svg +5 -5
- package/docs/images/logos/svelte.svg +4 -4
- package/docs/images/logos/vue.svg +5 -5
- package/docs/insforge-instructions-sdk.md +89 -88
- package/docs/introduction.mdx +45 -45
- package/docs/logo/dark.svg +22 -22
- package/docs/logo/light.svg +20 -20
- package/docs/partnership.mdx +651 -646
- package/docs/quickstart.mdx +82 -82
- package/docs/showcase.mdx +52 -52
- package/docs/snippets/sdk-installation.mdx +21 -21
- package/docs/snippets/service-icons.mdx +27 -27
- package/examples/oauth/frontend-oauth-example.html +250 -250
- package/examples/response-examples.md +443 -443
- package/frontend/components.json +17 -17
- package/frontend/package.json +69 -69
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -6
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -6
- package/frontend/src/assets/icons/checked.svg +3 -3
- package/frontend/src/assets/icons/connected.svg +3 -3
- package/frontend/src/assets/icons/error.svg +3 -3
- package/frontend/src/assets/icons/loader.svg +9 -9
- package/frontend/src/assets/icons/pencil.svg +4 -4
- package/frontend/src/assets/icons/refresh.svg +4 -4
- package/frontend/src/assets/icons/step_active.svg +3 -3
- package/frontend/src/assets/icons/step_inactive.svg +11 -11
- package/frontend/src/assets/icons/warning.svg +3 -3
- package/frontend/src/assets/logos/apple.svg +3 -3
- package/frontend/src/assets/logos/claude_code.svg +3 -3
- package/frontend/src/assets/logos/cline.svg +6 -6
- package/frontend/src/assets/logos/cursor.svg +20 -20
- package/frontend/src/assets/logos/discord.svg +8 -8
- package/frontend/src/assets/logos/facebook.svg +3 -3
- package/frontend/src/assets/logos/gemini.svg +19 -19
- package/frontend/src/assets/logos/github.svg +5 -5
- package/frontend/src/assets/logos/google.svg +13 -13
- package/frontend/src/assets/logos/grok.svg +10 -10
- package/frontend/src/assets/logos/insforge_dark.svg +15 -15
- package/frontend/src/assets/logos/insforge_light.svg +15 -15
- package/frontend/src/assets/logos/instagram.svg +1 -1
- package/frontend/src/assets/logos/linkedin.svg +3 -3
- package/frontend/src/assets/logos/openai.svg +10 -10
- package/frontend/src/assets/logos/roo_code.svg +9 -9
- package/frontend/src/assets/logos/spotify.svg +16 -16
- package/frontend/src/assets/logos/tiktok.svg +5 -5
- package/frontend/src/assets/logos/trae.svg +3 -3
- package/frontend/src/assets/logos/windsurf.svg +10 -10
- package/frontend/src/assets/logos/x.svg +3 -3
- package/frontend/src/components/layout/AppHeader.tsx +9 -10
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +1 -0
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +6 -0
- package/frontend/src/features/auth/helpers.tsx +8 -0
- package/frontend/src/features/auth/{page → pages}/UsersPage.tsx +0 -28
- package/frontend/src/features/database/components/SQLModal.tsx +75 -0
- package/frontend/src/features/database/components/TableForm.tsx +0 -4
- package/frontend/src/features/database/hooks/useDatabase.ts +66 -0
- package/frontend/src/features/database/hooks/useTables.ts +32 -28
- package/frontend/src/features/database/index.ts +1 -0
- package/frontend/src/features/database/{page → pages}/FunctionsPage.tsx +29 -37
- package/frontend/src/features/database/{page → pages}/IndexesPage.tsx +35 -47
- package/frontend/src/features/database/{page → pages}/PoliciesPage.tsx +43 -54
- package/frontend/src/features/database/{page → pages}/TablesPage.tsx +0 -42
- package/frontend/src/features/database/{page → pages}/TriggersPage.tsx +35 -47
- package/frontend/src/features/database/services/advance.service.ts +0 -26
- package/frontend/src/features/database/services/database.service.ts +55 -0
- package/frontend/src/features/database/services/table.service.ts +0 -6
- package/frontend/src/features/functions/{page → pages}/FunctionsPage.tsx +21 -44
- package/frontend/src/features/functions/{page → pages}/SecretsPage.tsx +11 -9
- package/frontend/src/features/logs/hooks/useMcpUsage.ts +13 -66
- package/frontend/src/features/realtime/components/ChannelRow.tsx +83 -0
- package/frontend/src/features/realtime/components/EditChannelModal.tsx +246 -0
- package/frontend/src/features/realtime/components/MessageRow.tsx +85 -0
- package/frontend/src/features/realtime/components/RealtimeEmptyState.tsx +30 -0
- package/frontend/src/features/realtime/hooks/useRealtime.ts +218 -0
- package/frontend/src/features/realtime/index.ts +11 -0
- package/frontend/src/features/realtime/pages/RealtimeChannelsPage.tsx +172 -0
- package/frontend/src/features/realtime/pages/RealtimeMessagesPage.tsx +211 -0
- package/frontend/src/features/realtime/pages/RealtimePermissionsPage.tsx +191 -0
- package/frontend/src/features/realtime/services/realtime.service.ts +107 -0
- package/frontend/src/features/storage/{page → pages}/StoragePage.tsx +1 -29
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +3 -3
- package/frontend/src/features/visualizer/{page → pages}/VisualizerPage.tsx +1 -35
- package/frontend/src/lib/contexts/SocketContext.tsx +119 -75
- package/frontend/src/lib/routing/AppRoutes.tsx +35 -20
- package/frontend/src/lib/utils/cloudMessaging.ts +1 -1
- package/frontend/src/lib/utils/menuItems.ts +24 -0
- package/frontend/src/lib/utils/utils.ts +14 -1
- package/frontend/tsconfig.json +25 -25
- package/frontend/tsconfig.node.json +9 -9
- package/functions/deno.json +24 -24
- package/functions/server.ts +315 -315
- package/i18n/README.ar.md +130 -130
- package/i18n/README.de.md +130 -130
- package/i18n/README.es.md +154 -154
- package/i18n/README.fr.md +134 -134
- package/i18n/README.hi.md +129 -129
- package/i18n/README.ja.md +174 -174
- package/i18n/README.ko.md +136 -136
- package/i18n/README.pt-BR.md +131 -131
- package/i18n/README.ru.md +129 -129
- package/i18n/README.zh-CN.md +133 -133
- package/openapi/ai.yaml +715 -715
- package/openapi/auth.yaml +1244 -1244
- package/openapi/email.yaml +158 -0
- package/openapi/functions.yaml +475 -475
- package/openapi/health.yaml +29 -29
- package/openapi/logs.yaml +223 -223
- package/openapi/metadata.yaml +177 -177
- package/openapi/realtime.yaml +699 -0
- package/openapi/records.yaml +381 -381
- package/openapi/secrets.yaml +370 -370
- package/openapi/storage.yaml +875 -875
- package/openapi/tables.yaml +463 -463
- package/package.json +97 -97
- package/shared-schemas/package.json +31 -31
- package/shared-schemas/src/ai.schema.ts +63 -59
- package/shared-schemas/src/auth-api.schema.ts +352 -339
- package/shared-schemas/src/auth.schema.ts +1 -1
- package/shared-schemas/src/database-api.schema.ts +32 -1
- package/shared-schemas/src/database.schema.ts +39 -0
- package/shared-schemas/src/docs.schema.ts +26 -0
- package/shared-schemas/src/email-api.schema.ts +30 -0
- package/shared-schemas/src/index.ts +4 -0
- package/shared-schemas/src/metadata.schema.ts +9 -0
- package/shared-schemas/src/realtime-api.schema.ts +111 -0
- package/shared-schemas/src/realtime.schema.ts +143 -0
- package/shared-schemas/tsconfig.json +21 -21
- package/tsconfig.json +7 -7
- package/zeabur/README.md +13 -13
- package/zeabur/template.yml +1032 -1032
- package/.cursor/rules/cursor-rules.mdc +0 -94
- package/frontend/src/features/database/hooks/useFullMetadata.ts +0 -18
- package/test-gemini.sh +0 -35
- package/test-usage-admin.sh +0 -57
- package/test-usage.sh +0 -50
- /package/frontend/src/features/ai/{page → pages}/AIPage.tsx +0 -0
- /package/frontend/src/features/auth/{page → pages}/AuthMethodsPage.tsx +0 -0
- /package/frontend/src/features/auth/{page → pages}/ConfigurationPage.tsx +0 -0
- /package/frontend/src/features/dashboard/{page → pages}/DashboardPage.tsx +0 -0
- /package/frontend/src/features/database/{page → pages}/SQLEditorPage.tsx +0 -0
- /package/frontend/src/features/database/{page → pages}/TemplatesPage.tsx +0 -0
- /package/frontend/src/features/login/{page → pages}/CloudLoginPage.tsx +0 -0
- /package/frontend/src/features/login/{page → pages}/LoginPage.tsx +0 -0
- /package/frontend/src/features/logs/{page → pages}/AuditsPage.tsx +0 -0
- /package/frontend/src/features/logs/{page → pages}/LogsPage.tsx +0 -0
- /package/frontend/src/features/logs/{page → pages}/MCPLogsPage.tsx +0 -0
package/openapi/storage.yaml
CHANGED
|
@@ -1,876 +1,876 @@
|
|
|
1
|
-
openapi: 3.0.3
|
|
2
|
-
info:
|
|
3
|
-
title: Insforge Storage API
|
|
4
|
-
version: 2.0.0
|
|
5
|
-
description: Bucket-based storage system similar to S3
|
|
6
|
-
|
|
7
|
-
paths:
|
|
8
|
-
/api/storage/buckets:
|
|
9
|
-
get:
|
|
10
|
-
summary: List All Buckets
|
|
11
|
-
tags:
|
|
12
|
-
- Admin
|
|
13
|
-
security:
|
|
14
|
-
- apiKey: []
|
|
15
|
-
responses:
|
|
16
|
-
'200':
|
|
17
|
-
description: List of bucket names
|
|
18
|
-
content:
|
|
19
|
-
application/json:
|
|
20
|
-
schema:
|
|
21
|
-
type: object
|
|
22
|
-
properties:
|
|
23
|
-
buckets:
|
|
24
|
-
type: array
|
|
25
|
-
items:
|
|
26
|
-
type: string
|
|
27
|
-
example: ["avatars", "documents", "uploads"]
|
|
28
|
-
example:
|
|
29
|
-
buckets: ["avatars", "documents", "uploads", "public", "private"]
|
|
30
|
-
|
|
31
|
-
post:
|
|
32
|
-
summary: Create New Bucket
|
|
33
|
-
tags:
|
|
34
|
-
- Admin
|
|
35
|
-
security:
|
|
36
|
-
- apiKey: []
|
|
37
|
-
requestBody:
|
|
38
|
-
required: true
|
|
39
|
-
content:
|
|
40
|
-
application/json:
|
|
41
|
-
schema:
|
|
42
|
-
type: object
|
|
43
|
-
required:
|
|
44
|
-
- bucketName
|
|
45
|
-
properties:
|
|
46
|
-
bucketName:
|
|
47
|
-
type: string
|
|
48
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
49
|
-
description: Bucket name (alphanumeric, underscore, and hyphen only)
|
|
50
|
-
example: avatars
|
|
51
|
-
isPublic:
|
|
52
|
-
type: boolean
|
|
53
|
-
description: Whether the bucket is publicly accessible
|
|
54
|
-
default: true
|
|
55
|
-
example: true
|
|
56
|
-
responses:
|
|
57
|
-
'201':
|
|
58
|
-
description: Bucket created successfully
|
|
59
|
-
content:
|
|
60
|
-
application/json:
|
|
61
|
-
schema:
|
|
62
|
-
type: object
|
|
63
|
-
properties:
|
|
64
|
-
message:
|
|
65
|
-
type: string
|
|
66
|
-
example: "Bucket created successfully"
|
|
67
|
-
bucketName:
|
|
68
|
-
type: string
|
|
69
|
-
example: avatars
|
|
70
|
-
example:
|
|
71
|
-
message: "Bucket created successfully"
|
|
72
|
-
bucket: "avatars"
|
|
73
|
-
'400':
|
|
74
|
-
description: Invalid bucket name
|
|
75
|
-
content:
|
|
76
|
-
application/json:
|
|
77
|
-
schema:
|
|
78
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
79
|
-
example:
|
|
80
|
-
error: "INVALID_BUCKET_NAME"
|
|
81
|
-
message: "Bucket name must contain only alphanumeric characters, underscores, and hyphens"
|
|
82
|
-
statusCode: 400
|
|
83
|
-
nextActions: "Use a valid bucket name format"
|
|
84
|
-
'409':
|
|
85
|
-
description: Bucket already exists
|
|
86
|
-
content:
|
|
87
|
-
application/json:
|
|
88
|
-
schema:
|
|
89
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
90
|
-
example:
|
|
91
|
-
error: "BUCKET_EXISTS"
|
|
92
|
-
message: "Bucket 'avatars' already exists"
|
|
93
|
-
statusCode: 409
|
|
94
|
-
nextActions: "Choose a different bucket name"
|
|
95
|
-
|
|
96
|
-
/api/storage/buckets/{bucketName}:
|
|
97
|
-
patch:
|
|
98
|
-
summary: Update Bucket
|
|
99
|
-
tags:
|
|
100
|
-
- Admin
|
|
101
|
-
security:
|
|
102
|
-
- apiKey: []
|
|
103
|
-
parameters:
|
|
104
|
-
- name: bucketName
|
|
105
|
-
in: path
|
|
106
|
-
required: true
|
|
107
|
-
schema:
|
|
108
|
-
type: string
|
|
109
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
110
|
-
example: avatars
|
|
111
|
-
requestBody:
|
|
112
|
-
required: true
|
|
113
|
-
content:
|
|
114
|
-
application/json:
|
|
115
|
-
schema:
|
|
116
|
-
type: object
|
|
117
|
-
required:
|
|
118
|
-
- is_public
|
|
119
|
-
properties:
|
|
120
|
-
isPublic:
|
|
121
|
-
type: boolean
|
|
122
|
-
description: Whether the bucket should be publicly accessible
|
|
123
|
-
example: true
|
|
124
|
-
responses:
|
|
125
|
-
'200':
|
|
126
|
-
description: Bucket visibility updated successfully
|
|
127
|
-
content:
|
|
128
|
-
application/json:
|
|
129
|
-
schema:
|
|
130
|
-
type: object
|
|
131
|
-
properties:
|
|
132
|
-
message:
|
|
133
|
-
type: string
|
|
134
|
-
example: "Bucket visibility updated"
|
|
135
|
-
bucket:
|
|
136
|
-
type: string
|
|
137
|
-
example: avatars
|
|
138
|
-
isPublic:
|
|
139
|
-
type: boolean
|
|
140
|
-
example: true
|
|
141
|
-
example:
|
|
142
|
-
message: "Bucket visibility updated"
|
|
143
|
-
bucket: "avatars"
|
|
144
|
-
isPublic: true
|
|
145
|
-
'404':
|
|
146
|
-
description: Bucket not found
|
|
147
|
-
content:
|
|
148
|
-
application/json:
|
|
149
|
-
schema:
|
|
150
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
151
|
-
example:
|
|
152
|
-
error: "BUCKET_NOT_FOUND"
|
|
153
|
-
message: "Bucket 'nonexistent' does not exist"
|
|
154
|
-
statusCode: 404
|
|
155
|
-
nextActions: "Check bucket name and try again"
|
|
156
|
-
|
|
157
|
-
/api/storage/buckets/{bucketName}/objects:
|
|
158
|
-
get:
|
|
159
|
-
summary: List Objects in Bucket
|
|
160
|
-
tags:
|
|
161
|
-
- Admin
|
|
162
|
-
security:
|
|
163
|
-
- apiKey: []
|
|
164
|
-
parameters:
|
|
165
|
-
- name: bucketName
|
|
166
|
-
in: path
|
|
167
|
-
required: true
|
|
168
|
-
schema:
|
|
169
|
-
type: string
|
|
170
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
171
|
-
example: avatars
|
|
172
|
-
- name: prefix
|
|
173
|
-
in: query
|
|
174
|
-
required: false
|
|
175
|
-
schema:
|
|
176
|
-
type: string
|
|
177
|
-
description: Filter objects by key prefix
|
|
178
|
-
example: users/
|
|
179
|
-
- name: limit
|
|
180
|
-
in: query
|
|
181
|
-
required: false
|
|
182
|
-
schema:
|
|
183
|
-
type: integer
|
|
184
|
-
minimum: 1
|
|
185
|
-
maximum: 1000
|
|
186
|
-
default: 100
|
|
187
|
-
- name: offset
|
|
188
|
-
in: query
|
|
189
|
-
required: false
|
|
190
|
-
schema:
|
|
191
|
-
type: integer
|
|
192
|
-
minimum: 0
|
|
193
|
-
default: 0
|
|
194
|
-
responses:
|
|
195
|
-
'200':
|
|
196
|
-
description: List of objects in bucket
|
|
197
|
-
content:
|
|
198
|
-
application/json:
|
|
199
|
-
schema:
|
|
200
|
-
type: object
|
|
201
|
-
properties:
|
|
202
|
-
data:
|
|
203
|
-
type: array
|
|
204
|
-
items:
|
|
205
|
-
$ref: '#/components/schemas/StoredFile'
|
|
206
|
-
pagination:
|
|
207
|
-
type: object
|
|
208
|
-
properties:
|
|
209
|
-
offset:
|
|
210
|
-
type: integer
|
|
211
|
-
example: 0
|
|
212
|
-
limit:
|
|
213
|
-
type: integer
|
|
214
|
-
example: 100
|
|
215
|
-
total:
|
|
216
|
-
type: integer
|
|
217
|
-
example: 2
|
|
218
|
-
nextActions:
|
|
219
|
-
type: string
|
|
220
|
-
example: "You can use PUT /api/storage/buckets/:bucketName/objects/:objectKey to upload with a specific key, or POST /api/storage/buckets/:bucketName/objects to upload with auto-generated key, and GET /api/storage/buckets/:bucketName/objects/:objectKey to download an object."
|
|
221
|
-
example:
|
|
222
|
-
data:
|
|
223
|
-
- bucket: "avatars"
|
|
224
|
-
key: "users/user123.jpg"
|
|
225
|
-
size: 102400
|
|
226
|
-
mimeType: "image/jpeg"
|
|
227
|
-
uploadedAt: "2024-01-15T10:30:00Z"
|
|
228
|
-
url: "/api/storage/buckets/avatars/objects/users/user123.jpg"
|
|
229
|
-
- bucket: "avatars"
|
|
230
|
-
key: "users/user456.png"
|
|
231
|
-
size: 204800
|
|
232
|
-
mimeType: "image/png"
|
|
233
|
-
uploadedAt: "2024-01-16T11:00:00Z"
|
|
234
|
-
url: "/api/storage/buckets/avatars/objects/users/user456.png"
|
|
235
|
-
pagination:
|
|
236
|
-
offset: 0
|
|
237
|
-
limit: 100
|
|
238
|
-
total: 2
|
|
239
|
-
nextActions: "You can use PUT /api/storage/buckets/:bucketName/objects/:objectKey to upload with a specific key, or POST /api/storage/buckets/:bucketName/objects to upload with auto-generated key, and GET /api/storage/buckets/:bucketName/objects/:objectKey to download an object."
|
|
240
|
-
|
|
241
|
-
delete:
|
|
242
|
-
summary: Delete Bucket
|
|
243
|
-
tags:
|
|
244
|
-
- Admin
|
|
245
|
-
security:
|
|
246
|
-
- apiKey: []
|
|
247
|
-
parameters:
|
|
248
|
-
- name: bucketName
|
|
249
|
-
in: path
|
|
250
|
-
required: true
|
|
251
|
-
schema:
|
|
252
|
-
type: string
|
|
253
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
254
|
-
example: avatars
|
|
255
|
-
responses:
|
|
256
|
-
'200':
|
|
257
|
-
description: Bucket deleted successfully
|
|
258
|
-
content:
|
|
259
|
-
application/json:
|
|
260
|
-
schema:
|
|
261
|
-
type: object
|
|
262
|
-
properties:
|
|
263
|
-
message:
|
|
264
|
-
type: string
|
|
265
|
-
example:
|
|
266
|
-
message: "Bucket deleted successfully"
|
|
267
|
-
'404':
|
|
268
|
-
description: Bucket not found
|
|
269
|
-
content:
|
|
270
|
-
application/json:
|
|
271
|
-
schema:
|
|
272
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
273
|
-
example:
|
|
274
|
-
error: "BUCKET_NOT_FOUND"
|
|
275
|
-
message: "Bucket 'nonexistent' does not exist"
|
|
276
|
-
statusCode: 404
|
|
277
|
-
nextActions: "Check bucket name and try again"
|
|
278
|
-
|
|
279
|
-
post:
|
|
280
|
-
summary: Upload Object with Auto-Generated Key
|
|
281
|
-
tags:
|
|
282
|
-
- Client
|
|
283
|
-
security:
|
|
284
|
-
- apiKey: []
|
|
285
|
-
parameters:
|
|
286
|
-
- name: bucketName
|
|
287
|
-
in: path
|
|
288
|
-
required: true
|
|
289
|
-
schema:
|
|
290
|
-
type: string
|
|
291
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
292
|
-
example: avatars
|
|
293
|
-
requestBody:
|
|
294
|
-
required: true
|
|
295
|
-
content:
|
|
296
|
-
multipart/form-data:
|
|
297
|
-
schema:
|
|
298
|
-
type: object
|
|
299
|
-
properties:
|
|
300
|
-
file:
|
|
301
|
-
type: string
|
|
302
|
-
format: binary
|
|
303
|
-
description: File to upload
|
|
304
|
-
required:
|
|
305
|
-
- file
|
|
306
|
-
responses:
|
|
307
|
-
'201':
|
|
308
|
-
description: Object uploaded successfully with auto-generated key
|
|
309
|
-
content:
|
|
310
|
-
application/json:
|
|
311
|
-
schema:
|
|
312
|
-
$ref: '#/components/schemas/StoredFile'
|
|
313
|
-
example:
|
|
314
|
-
bucket: "avatars"
|
|
315
|
-
key: "image-1737546841234-a3f2b1.jpg"
|
|
316
|
-
size: 102400
|
|
317
|
-
mimeType: "image/jpeg"
|
|
318
|
-
uploadedAt: "2024-01-21T10:30:00Z"
|
|
319
|
-
url: "/api/storage/buckets/avatars/objects/image-1737546841234-a3f2b1.jpg"
|
|
320
|
-
'400':
|
|
321
|
-
description: Invalid bucket name or file
|
|
322
|
-
content:
|
|
323
|
-
application/json:
|
|
324
|
-
schema:
|
|
325
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
326
|
-
example:
|
|
327
|
-
error: "INVALID_FILE"
|
|
328
|
-
message: "No file provided in the request"
|
|
329
|
-
statusCode: 400
|
|
330
|
-
nextActions: "Include a file in the multipart form data"
|
|
331
|
-
'404':
|
|
332
|
-
description: Bucket not found
|
|
333
|
-
content:
|
|
334
|
-
application/json:
|
|
335
|
-
schema:
|
|
336
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
337
|
-
example:
|
|
338
|
-
error: "BUCKET_NOT_FOUND"
|
|
339
|
-
message: "Bucket 'nonexistent' does not exist"
|
|
340
|
-
statusCode: 404
|
|
341
|
-
nextActions: "Create the bucket first"
|
|
342
|
-
|
|
343
|
-
/api/storage/buckets/{bucketName}/upload-strategy:
|
|
344
|
-
post:
|
|
345
|
-
summary: Get Upload Strategy (Direct or Presigned URL)
|
|
346
|
-
description: Returns upload strategy based on storage backend (S3 returns presigned URLs, local returns direct upload endpoints)
|
|
347
|
-
tags:
|
|
348
|
-
- Client
|
|
349
|
-
security:
|
|
350
|
-
- apiKey: []
|
|
351
|
-
parameters:
|
|
352
|
-
- name: bucketName
|
|
353
|
-
in: path
|
|
354
|
-
required: true
|
|
355
|
-
schema:
|
|
356
|
-
type: string
|
|
357
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
358
|
-
example: avatars
|
|
359
|
-
requestBody:
|
|
360
|
-
required: true
|
|
361
|
-
content:
|
|
362
|
-
application/json:
|
|
363
|
-
schema:
|
|
364
|
-
type: object
|
|
365
|
-
required:
|
|
366
|
-
- filename
|
|
367
|
-
properties:
|
|
368
|
-
filename:
|
|
369
|
-
type: string
|
|
370
|
-
description: Original filename for generating unique key
|
|
371
|
-
example: profile-photo.jpg
|
|
372
|
-
contentType:
|
|
373
|
-
type: string
|
|
374
|
-
description: MIME type of the file
|
|
375
|
-
example: image/jpeg
|
|
376
|
-
size:
|
|
377
|
-
type: integer
|
|
378
|
-
description: File size in bytes
|
|
379
|
-
example: 102400
|
|
380
|
-
responses:
|
|
381
|
-
'200':
|
|
382
|
-
description: Upload strategy details
|
|
383
|
-
content:
|
|
384
|
-
application/json:
|
|
385
|
-
schema:
|
|
386
|
-
$ref: '#/components/schemas/UploadStrategy'
|
|
387
|
-
examples:
|
|
388
|
-
s3:
|
|
389
|
-
summary: S3 Backend Response
|
|
390
|
-
value:
|
|
391
|
-
method: presigned
|
|
392
|
-
uploadUrl: https://s3-bucket.amazonaws.com/
|
|
393
|
-
fields:
|
|
394
|
-
bucket: my-s3-bucket
|
|
395
|
-
key: app-key/avatars/profile-photo-1234567890-abc123.jpg
|
|
396
|
-
X-Amz-Algorithm: AWS4-HMAC-SHA256
|
|
397
|
-
X-Amz-Credential: AKIA.../20250905/us-east-2/s3/aws4_request
|
|
398
|
-
X-Amz-Date: 20250905T000000Z
|
|
399
|
-
Policy: eyJ...
|
|
400
|
-
X-Amz-Signature: abc123...
|
|
401
|
-
key: profile-photo-1234567890-abc123.jpg
|
|
402
|
-
confirmRequired: true
|
|
403
|
-
confirmUrl: /api/storage/buckets/avatars/objects/profile-photo-1234567890-abc123.jpg/confirm-upload
|
|
404
|
-
expiresAt: "2025-09-05T01:00:00Z"
|
|
405
|
-
local:
|
|
406
|
-
summary: Local Storage Response
|
|
407
|
-
value:
|
|
408
|
-
method: direct
|
|
409
|
-
uploadUrl: /api/storage/buckets/avatars/objects/profile-photo-1234567890-abc123.jpg
|
|
410
|
-
key: profile-photo-1234567890-abc123.jpg
|
|
411
|
-
confirmRequired: false
|
|
412
|
-
'404':
|
|
413
|
-
description: Bucket not found
|
|
414
|
-
content:
|
|
415
|
-
application/json:
|
|
416
|
-
schema:
|
|
417
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
418
|
-
|
|
419
|
-
/api/storage/buckets/{bucketName}/objects/{objectKey}:
|
|
420
|
-
put:
|
|
421
|
-
summary: Upload Object
|
|
422
|
-
tags:
|
|
423
|
-
- Client
|
|
424
|
-
security:
|
|
425
|
-
- apiKey: []
|
|
426
|
-
parameters:
|
|
427
|
-
- name: bucketName
|
|
428
|
-
in: path
|
|
429
|
-
required: true
|
|
430
|
-
schema:
|
|
431
|
-
type: string
|
|
432
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
433
|
-
example: avatars
|
|
434
|
-
- name: objectKey
|
|
435
|
-
in: path
|
|
436
|
-
required: true
|
|
437
|
-
schema:
|
|
438
|
-
type: string
|
|
439
|
-
example: user123.jpg
|
|
440
|
-
description: Object key (can include forward slashes for pseudo-folders)
|
|
441
|
-
requestBody:
|
|
442
|
-
required: true
|
|
443
|
-
content:
|
|
444
|
-
multipart/form-data:
|
|
445
|
-
schema:
|
|
446
|
-
type: object
|
|
447
|
-
properties:
|
|
448
|
-
file:
|
|
449
|
-
type: string
|
|
450
|
-
format: binary
|
|
451
|
-
description: File to upload
|
|
452
|
-
required:
|
|
453
|
-
- file
|
|
454
|
-
responses:
|
|
455
|
-
'201':
|
|
456
|
-
description: Object uploaded successfully
|
|
457
|
-
content:
|
|
458
|
-
application/json:
|
|
459
|
-
schema:
|
|
460
|
-
$ref: '#/components/schemas/StoredFile'
|
|
461
|
-
example:
|
|
462
|
-
bucket: "avatars"
|
|
463
|
-
key: "user123.jpg"
|
|
464
|
-
size: 102400
|
|
465
|
-
mimeType: "image/jpeg"
|
|
466
|
-
uploadedAt: "2024-01-21T10:30:00Z"
|
|
467
|
-
url: "/api/storage/buckets/avatars/objects/user123.jpg"
|
|
468
|
-
'400':
|
|
469
|
-
description: Invalid bucket name, key, or file
|
|
470
|
-
content:
|
|
471
|
-
application/json:
|
|
472
|
-
schema:
|
|
473
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
474
|
-
example:
|
|
475
|
-
error: "INVALID_FILE"
|
|
476
|
-
message: "No file provided in the request"
|
|
477
|
-
statusCode: 400
|
|
478
|
-
nextActions: "Include a file in the multipart form data"
|
|
479
|
-
'404':
|
|
480
|
-
description: Bucket not found
|
|
481
|
-
content:
|
|
482
|
-
application/json:
|
|
483
|
-
schema:
|
|
484
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
485
|
-
example:
|
|
486
|
-
error: "BUCKET_NOT_FOUND"
|
|
487
|
-
message: "Bucket 'nonexistent' does not exist"
|
|
488
|
-
statusCode: 404
|
|
489
|
-
nextActions: "Create the bucket first"
|
|
490
|
-
|
|
491
|
-
get:
|
|
492
|
-
summary: Download Object
|
|
493
|
-
tags:
|
|
494
|
-
- Client
|
|
495
|
-
security:
|
|
496
|
-
- apiKey: []
|
|
497
|
-
parameters:
|
|
498
|
-
- name: bucketName
|
|
499
|
-
in: path
|
|
500
|
-
required: true
|
|
501
|
-
schema:
|
|
502
|
-
type: string
|
|
503
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
504
|
-
example: avatars
|
|
505
|
-
- name: key
|
|
506
|
-
in: path
|
|
507
|
-
required: true
|
|
508
|
-
schema:
|
|
509
|
-
type: string
|
|
510
|
-
example: user123.jpg
|
|
511
|
-
responses:
|
|
512
|
-
'200':
|
|
513
|
-
description: File content
|
|
514
|
-
content:
|
|
515
|
-
'*/*':
|
|
516
|
-
schema:
|
|
517
|
-
type: string
|
|
518
|
-
format: binary
|
|
519
|
-
headers:
|
|
520
|
-
Content-Type:
|
|
521
|
-
schema:
|
|
522
|
-
type: string
|
|
523
|
-
description: MIME type of the file
|
|
524
|
-
Content-Length:
|
|
525
|
-
schema:
|
|
526
|
-
type: integer
|
|
527
|
-
description: Size of the file in bytes
|
|
528
|
-
'404':
|
|
529
|
-
description: Object not found
|
|
530
|
-
content:
|
|
531
|
-
application/json:
|
|
532
|
-
schema:
|
|
533
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
534
|
-
example:
|
|
535
|
-
error: "OBJECT_NOT_FOUND"
|
|
536
|
-
message: "Object 'user123.jpg' not found in bucket 'avatars'"
|
|
537
|
-
statusCode: 404
|
|
538
|
-
nextActions: "Check the bucket and key combination"
|
|
539
|
-
|
|
540
|
-
delete:
|
|
541
|
-
summary: Delete Object
|
|
542
|
-
tags:
|
|
543
|
-
- Client
|
|
544
|
-
security:
|
|
545
|
-
- apiKey: []
|
|
546
|
-
parameters:
|
|
547
|
-
- name: bucketName
|
|
548
|
-
in: path
|
|
549
|
-
required: true
|
|
550
|
-
schema:
|
|
551
|
-
type: string
|
|
552
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
553
|
-
example: avatars
|
|
554
|
-
- name: key
|
|
555
|
-
in: path
|
|
556
|
-
required: true
|
|
557
|
-
schema:
|
|
558
|
-
type: string
|
|
559
|
-
example: user123.jpg
|
|
560
|
-
responses:
|
|
561
|
-
'200':
|
|
562
|
-
description: Object deleted successfully
|
|
563
|
-
content:
|
|
564
|
-
application/json:
|
|
565
|
-
schema:
|
|
566
|
-
type: object
|
|
567
|
-
properties:
|
|
568
|
-
message:
|
|
569
|
-
type: string
|
|
570
|
-
example:
|
|
571
|
-
message: "Object deleted successfully"
|
|
572
|
-
'404':
|
|
573
|
-
description: Object not found
|
|
574
|
-
content:
|
|
575
|
-
application/json:
|
|
576
|
-
schema:
|
|
577
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
578
|
-
example:
|
|
579
|
-
error: "OBJECT_NOT_FOUND"
|
|
580
|
-
message: "Object 'user123.jpg' not found in bucket 'avatars'"
|
|
581
|
-
statusCode: 404
|
|
582
|
-
nextActions: "Check the bucket and key combination"
|
|
583
|
-
|
|
584
|
-
/api/storage/buckets/{bucketName}/objects/{objectKey}/confirm-upload:
|
|
585
|
-
post:
|
|
586
|
-
summary: Confirm Presigned Upload
|
|
587
|
-
description: Confirms that a file was successfully uploaded to S3 using presigned URL
|
|
588
|
-
tags:
|
|
589
|
-
- Client
|
|
590
|
-
security:
|
|
591
|
-
- apiKey: []
|
|
592
|
-
parameters:
|
|
593
|
-
- name: bucketName
|
|
594
|
-
in: path
|
|
595
|
-
required: true
|
|
596
|
-
schema:
|
|
597
|
-
type: string
|
|
598
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
599
|
-
example: avatars
|
|
600
|
-
- name: objectKey
|
|
601
|
-
in: path
|
|
602
|
-
required: true
|
|
603
|
-
schema:
|
|
604
|
-
type: string
|
|
605
|
-
example: profile-photo-1234567890-abc123.jpg
|
|
606
|
-
requestBody:
|
|
607
|
-
required: true
|
|
608
|
-
content:
|
|
609
|
-
application/json:
|
|
610
|
-
schema:
|
|
611
|
-
type: object
|
|
612
|
-
required:
|
|
613
|
-
- size
|
|
614
|
-
properties:
|
|
615
|
-
size:
|
|
616
|
-
type: integer
|
|
617
|
-
description: File size in bytes
|
|
618
|
-
example: 102400
|
|
619
|
-
contentType:
|
|
620
|
-
type: string
|
|
621
|
-
description: MIME type of the file
|
|
622
|
-
example: image/jpeg
|
|
623
|
-
etag:
|
|
624
|
-
type: string
|
|
625
|
-
description: S3 ETag of the uploaded object (optional)
|
|
626
|
-
example: "9bb58f26192e4ba00f01e2e7b136bbd8"
|
|
627
|
-
responses:
|
|
628
|
-
'201':
|
|
629
|
-
description: Upload confirmed successfully
|
|
630
|
-
content:
|
|
631
|
-
application/json:
|
|
632
|
-
schema:
|
|
633
|
-
$ref: '#/components/schemas/StoredFile'
|
|
634
|
-
'404':
|
|
635
|
-
description: Upload not found
|
|
636
|
-
content:
|
|
637
|
-
application/json:
|
|
638
|
-
schema:
|
|
639
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
640
|
-
example:
|
|
641
|
-
error: "UPLOAD_NOT_FOUND"
|
|
642
|
-
message: "Upload not found for key 'profile-photo.jpg' in bucket 'avatars'"
|
|
643
|
-
statusCode: 404
|
|
644
|
-
'409':
|
|
645
|
-
description: Already confirmed
|
|
646
|
-
content:
|
|
647
|
-
application/json:
|
|
648
|
-
schema:
|
|
649
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
650
|
-
example:
|
|
651
|
-
error: "ALREADY_CONFIRMED"
|
|
652
|
-
message: "File 'profile-photo.jpg' already confirmed in bucket 'avatars'"
|
|
653
|
-
statusCode: 409
|
|
654
|
-
|
|
655
|
-
/api/storage/buckets/{bucketName}/objects/{objectKey}/download-strategy:
|
|
656
|
-
post:
|
|
657
|
-
summary: Get Download Strategy (Direct or Presigned URL)
|
|
658
|
-
description: |
|
|
659
|
-
Returns download strategy based on storage backend and bucket visibility.
|
|
660
|
-
- S3 with public bucket: Direct URLs (no presigning, better performance)
|
|
661
|
-
- S3 with private bucket: Presigned URLs with expiration
|
|
662
|
-
- Local storage: Always direct endpoints
|
|
663
|
-
tags:
|
|
664
|
-
- Client
|
|
665
|
-
security:
|
|
666
|
-
- apiKey: []
|
|
667
|
-
parameters:
|
|
668
|
-
- name: bucketName
|
|
669
|
-
in: path
|
|
670
|
-
required: true
|
|
671
|
-
schema:
|
|
672
|
-
type: string
|
|
673
|
-
pattern: '^[a-zA-Z0-9_-]+$'
|
|
674
|
-
example: avatars
|
|
675
|
-
- name: objectKey
|
|
676
|
-
in: path
|
|
677
|
-
required: true
|
|
678
|
-
schema:
|
|
679
|
-
type: string
|
|
680
|
-
example: profile-photo.jpg
|
|
681
|
-
requestBody:
|
|
682
|
-
content:
|
|
683
|
-
application/json:
|
|
684
|
-
schema:
|
|
685
|
-
type: object
|
|
686
|
-
properties:
|
|
687
|
-
expiresIn:
|
|
688
|
-
type: integer
|
|
689
|
-
description: URL expiration time in seconds (default 3600)
|
|
690
|
-
example: 3600
|
|
691
|
-
default: 3600
|
|
692
|
-
responses:
|
|
693
|
-
'200':
|
|
694
|
-
description: Download strategy details
|
|
695
|
-
content:
|
|
696
|
-
application/json:
|
|
697
|
-
schema:
|
|
698
|
-
$ref: '#/components/schemas/DownloadStrategy'
|
|
699
|
-
examples:
|
|
700
|
-
s3-public:
|
|
701
|
-
summary: S3 Public Bucket Response
|
|
702
|
-
value:
|
|
703
|
-
method: direct
|
|
704
|
-
url: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/public-assets/logo.png
|
|
705
|
-
s3-private:
|
|
706
|
-
summary: S3 Private Bucket Response
|
|
707
|
-
value:
|
|
708
|
-
method: presigned
|
|
709
|
-
url: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/avatars/profile.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
|
|
710
|
-
expiresAt: "2025-09-05T01:00:00Z"
|
|
711
|
-
local:
|
|
712
|
-
summary: Local Storage Response
|
|
713
|
-
value:
|
|
714
|
-
method: direct
|
|
715
|
-
url: /api/storage/buckets/avatars/objects/profile-photo.jpg
|
|
716
|
-
'404':
|
|
717
|
-
description: Object not found
|
|
718
|
-
content:
|
|
719
|
-
application/json:
|
|
720
|
-
schema:
|
|
721
|
-
$ref: '#/components/schemas/ErrorResponse'
|
|
722
|
-
|
|
723
|
-
components:
|
|
724
|
-
securitySchemes:
|
|
725
|
-
apiKey:
|
|
726
|
-
type: apiKey
|
|
727
|
-
in: header
|
|
728
|
-
name: x-api-key
|
|
729
|
-
|
|
730
|
-
schemas:
|
|
731
|
-
StoredFile:
|
|
732
|
-
type: object
|
|
733
|
-
properties:
|
|
734
|
-
bucket:
|
|
735
|
-
type: string
|
|
736
|
-
example: avatars
|
|
737
|
-
description: Name of the bucket containing the object
|
|
738
|
-
key:
|
|
739
|
-
type: string
|
|
740
|
-
example: user123.jpg
|
|
741
|
-
description: Unique key identifying the object within the bucket
|
|
742
|
-
size:
|
|
743
|
-
type: integer
|
|
744
|
-
example: 102400
|
|
745
|
-
description: Size of the file in bytes
|
|
746
|
-
mimeType:
|
|
747
|
-
type: string
|
|
748
|
-
example: image/jpeg
|
|
749
|
-
description: MIME type of the file
|
|
750
|
-
uploadedAt:
|
|
751
|
-
type: string
|
|
752
|
-
format: date-time
|
|
753
|
-
example: "2024-01-15T10:30:00Z"
|
|
754
|
-
description: ISO timestamp when the file was uploaded
|
|
755
|
-
url:
|
|
756
|
-
type: string
|
|
757
|
-
example: "/api/storage/buckets/avatars/objects/user123.jpg"
|
|
758
|
-
description: URL to download the file
|
|
759
|
-
required:
|
|
760
|
-
- bucket
|
|
761
|
-
- key
|
|
762
|
-
- size
|
|
763
|
-
- uploadedAt
|
|
764
|
-
- url
|
|
765
|
-
|
|
766
|
-
Pagination:
|
|
767
|
-
type: object
|
|
768
|
-
properties:
|
|
769
|
-
limit:
|
|
770
|
-
type: integer
|
|
771
|
-
example: 100
|
|
772
|
-
offset:
|
|
773
|
-
type: integer
|
|
774
|
-
example: 0
|
|
775
|
-
total:
|
|
776
|
-
type: integer
|
|
777
|
-
example: 1
|
|
778
|
-
required:
|
|
779
|
-
- limit
|
|
780
|
-
- offset
|
|
781
|
-
- total
|
|
782
|
-
|
|
783
|
-
UploadStrategy:
|
|
784
|
-
type: object
|
|
785
|
-
required:
|
|
786
|
-
- method
|
|
787
|
-
- uploadUrl
|
|
788
|
-
- key
|
|
789
|
-
- confirmRequired
|
|
790
|
-
properties:
|
|
791
|
-
method:
|
|
792
|
-
type: string
|
|
793
|
-
enum: [presigned, direct]
|
|
794
|
-
description: Upload method - presigned for S3, direct for local storage
|
|
795
|
-
example: presigned
|
|
796
|
-
uploadUrl:
|
|
797
|
-
type: string
|
|
798
|
-
description: URL to upload the file to
|
|
799
|
-
example: https://s3-bucket.amazonaws.com/
|
|
800
|
-
fields:
|
|
801
|
-
type: object
|
|
802
|
-
description: Form fields for presigned POST (S3 only)
|
|
803
|
-
additionalProperties: true
|
|
804
|
-
example:
|
|
805
|
-
bucket: my-s3-bucket
|
|
806
|
-
key: app-key/avatars/profile.jpg
|
|
807
|
-
X-Amz-Algorithm: AWS4-HMAC-SHA256
|
|
808
|
-
key:
|
|
809
|
-
type: string
|
|
810
|
-
description: Generated unique key for the file
|
|
811
|
-
example: profile-photo-1234567890-abc123.jpg
|
|
812
|
-
confirmRequired:
|
|
813
|
-
type: boolean
|
|
814
|
-
description: Whether upload confirmation is required
|
|
815
|
-
example: true
|
|
816
|
-
confirmUrl:
|
|
817
|
-
type: string
|
|
818
|
-
description: URL to confirm the upload (if confirmRequired is true)
|
|
819
|
-
example: /api/storage/buckets/avatars/objects/profile.jpg/confirm-upload
|
|
820
|
-
expiresAt:
|
|
821
|
-
type: string
|
|
822
|
-
format: date-time
|
|
823
|
-
description: Expiration time for presigned URL (S3 only)
|
|
824
|
-
example: "2025-09-05T01:00:00Z"
|
|
825
|
-
|
|
826
|
-
DownloadStrategy:
|
|
827
|
-
type: object
|
|
828
|
-
required:
|
|
829
|
-
- method
|
|
830
|
-
- url
|
|
831
|
-
properties:
|
|
832
|
-
method:
|
|
833
|
-
type: string
|
|
834
|
-
enum: [presigned, direct]
|
|
835
|
-
description: |
|
|
836
|
-
Download method:
|
|
837
|
-
- `direct`: Direct URL access (S3 public buckets or local storage)
|
|
838
|
-
- `presigned`: Secure URL with signature and expiration (S3 private buckets)
|
|
839
|
-
example: direct
|
|
840
|
-
url:
|
|
841
|
-
type: string
|
|
842
|
-
description: URL to download the file from
|
|
843
|
-
example: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/public-assets/logo.png
|
|
844
|
-
expiresAt:
|
|
845
|
-
type: string
|
|
846
|
-
format: date-time
|
|
847
|
-
description: Expiration time for presigned URLs (only present when method is 'presigned')
|
|
848
|
-
example: "2025-09-05T01:00:00Z"
|
|
849
|
-
headers:
|
|
850
|
-
type: object
|
|
851
|
-
description: Optional headers to include in the download request
|
|
852
|
-
additionalProperties: true
|
|
853
|
-
|
|
854
|
-
ErrorResponse:
|
|
855
|
-
type: object
|
|
856
|
-
required:
|
|
857
|
-
- error
|
|
858
|
-
- message
|
|
859
|
-
- statusCode
|
|
860
|
-
properties:
|
|
861
|
-
error:
|
|
862
|
-
type: string
|
|
863
|
-
description: Error code for programmatic handling
|
|
864
|
-
example: "VALIDATION_ERROR"
|
|
865
|
-
message:
|
|
866
|
-
type: string
|
|
867
|
-
description: Human-readable error message
|
|
868
|
-
example: "Invalid request"
|
|
869
|
-
statusCode:
|
|
870
|
-
type: integer
|
|
871
|
-
description: HTTP status code
|
|
872
|
-
example: 400
|
|
873
|
-
nextActions:
|
|
874
|
-
type: string
|
|
875
|
-
description: Suggested action to resolve the error
|
|
1
|
+
openapi: 3.0.3
|
|
2
|
+
info:
|
|
3
|
+
title: Insforge Storage API
|
|
4
|
+
version: 2.0.0
|
|
5
|
+
description: Bucket-based storage system similar to S3
|
|
6
|
+
|
|
7
|
+
paths:
|
|
8
|
+
/api/storage/buckets:
|
|
9
|
+
get:
|
|
10
|
+
summary: List All Buckets
|
|
11
|
+
tags:
|
|
12
|
+
- Admin
|
|
13
|
+
security:
|
|
14
|
+
- apiKey: []
|
|
15
|
+
responses:
|
|
16
|
+
'200':
|
|
17
|
+
description: List of bucket names
|
|
18
|
+
content:
|
|
19
|
+
application/json:
|
|
20
|
+
schema:
|
|
21
|
+
type: object
|
|
22
|
+
properties:
|
|
23
|
+
buckets:
|
|
24
|
+
type: array
|
|
25
|
+
items:
|
|
26
|
+
type: string
|
|
27
|
+
example: ["avatars", "documents", "uploads"]
|
|
28
|
+
example:
|
|
29
|
+
buckets: ["avatars", "documents", "uploads", "public", "private"]
|
|
30
|
+
|
|
31
|
+
post:
|
|
32
|
+
summary: Create New Bucket
|
|
33
|
+
tags:
|
|
34
|
+
- Admin
|
|
35
|
+
security:
|
|
36
|
+
- apiKey: []
|
|
37
|
+
requestBody:
|
|
38
|
+
required: true
|
|
39
|
+
content:
|
|
40
|
+
application/json:
|
|
41
|
+
schema:
|
|
42
|
+
type: object
|
|
43
|
+
required:
|
|
44
|
+
- bucketName
|
|
45
|
+
properties:
|
|
46
|
+
bucketName:
|
|
47
|
+
type: string
|
|
48
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
49
|
+
description: Bucket name (alphanumeric, underscore, and hyphen only)
|
|
50
|
+
example: avatars
|
|
51
|
+
isPublic:
|
|
52
|
+
type: boolean
|
|
53
|
+
description: Whether the bucket is publicly accessible
|
|
54
|
+
default: true
|
|
55
|
+
example: true
|
|
56
|
+
responses:
|
|
57
|
+
'201':
|
|
58
|
+
description: Bucket created successfully
|
|
59
|
+
content:
|
|
60
|
+
application/json:
|
|
61
|
+
schema:
|
|
62
|
+
type: object
|
|
63
|
+
properties:
|
|
64
|
+
message:
|
|
65
|
+
type: string
|
|
66
|
+
example: "Bucket created successfully"
|
|
67
|
+
bucketName:
|
|
68
|
+
type: string
|
|
69
|
+
example: avatars
|
|
70
|
+
example:
|
|
71
|
+
message: "Bucket created successfully"
|
|
72
|
+
bucket: "avatars"
|
|
73
|
+
'400':
|
|
74
|
+
description: Invalid bucket name
|
|
75
|
+
content:
|
|
76
|
+
application/json:
|
|
77
|
+
schema:
|
|
78
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
79
|
+
example:
|
|
80
|
+
error: "INVALID_BUCKET_NAME"
|
|
81
|
+
message: "Bucket name must contain only alphanumeric characters, underscores, and hyphens"
|
|
82
|
+
statusCode: 400
|
|
83
|
+
nextActions: "Use a valid bucket name format"
|
|
84
|
+
'409':
|
|
85
|
+
description: Bucket already exists
|
|
86
|
+
content:
|
|
87
|
+
application/json:
|
|
88
|
+
schema:
|
|
89
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
90
|
+
example:
|
|
91
|
+
error: "BUCKET_EXISTS"
|
|
92
|
+
message: "Bucket 'avatars' already exists"
|
|
93
|
+
statusCode: 409
|
|
94
|
+
nextActions: "Choose a different bucket name"
|
|
95
|
+
|
|
96
|
+
/api/storage/buckets/{bucketName}:
|
|
97
|
+
patch:
|
|
98
|
+
summary: Update Bucket
|
|
99
|
+
tags:
|
|
100
|
+
- Admin
|
|
101
|
+
security:
|
|
102
|
+
- apiKey: []
|
|
103
|
+
parameters:
|
|
104
|
+
- name: bucketName
|
|
105
|
+
in: path
|
|
106
|
+
required: true
|
|
107
|
+
schema:
|
|
108
|
+
type: string
|
|
109
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
110
|
+
example: avatars
|
|
111
|
+
requestBody:
|
|
112
|
+
required: true
|
|
113
|
+
content:
|
|
114
|
+
application/json:
|
|
115
|
+
schema:
|
|
116
|
+
type: object
|
|
117
|
+
required:
|
|
118
|
+
- is_public
|
|
119
|
+
properties:
|
|
120
|
+
isPublic:
|
|
121
|
+
type: boolean
|
|
122
|
+
description: Whether the bucket should be publicly accessible
|
|
123
|
+
example: true
|
|
124
|
+
responses:
|
|
125
|
+
'200':
|
|
126
|
+
description: Bucket visibility updated successfully
|
|
127
|
+
content:
|
|
128
|
+
application/json:
|
|
129
|
+
schema:
|
|
130
|
+
type: object
|
|
131
|
+
properties:
|
|
132
|
+
message:
|
|
133
|
+
type: string
|
|
134
|
+
example: "Bucket visibility updated"
|
|
135
|
+
bucket:
|
|
136
|
+
type: string
|
|
137
|
+
example: avatars
|
|
138
|
+
isPublic:
|
|
139
|
+
type: boolean
|
|
140
|
+
example: true
|
|
141
|
+
example:
|
|
142
|
+
message: "Bucket visibility updated"
|
|
143
|
+
bucket: "avatars"
|
|
144
|
+
isPublic: true
|
|
145
|
+
'404':
|
|
146
|
+
description: Bucket not found
|
|
147
|
+
content:
|
|
148
|
+
application/json:
|
|
149
|
+
schema:
|
|
150
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
151
|
+
example:
|
|
152
|
+
error: "BUCKET_NOT_FOUND"
|
|
153
|
+
message: "Bucket 'nonexistent' does not exist"
|
|
154
|
+
statusCode: 404
|
|
155
|
+
nextActions: "Check bucket name and try again"
|
|
156
|
+
|
|
157
|
+
/api/storage/buckets/{bucketName}/objects:
|
|
158
|
+
get:
|
|
159
|
+
summary: List Objects in Bucket
|
|
160
|
+
tags:
|
|
161
|
+
- Admin
|
|
162
|
+
security:
|
|
163
|
+
- apiKey: []
|
|
164
|
+
parameters:
|
|
165
|
+
- name: bucketName
|
|
166
|
+
in: path
|
|
167
|
+
required: true
|
|
168
|
+
schema:
|
|
169
|
+
type: string
|
|
170
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
171
|
+
example: avatars
|
|
172
|
+
- name: prefix
|
|
173
|
+
in: query
|
|
174
|
+
required: false
|
|
175
|
+
schema:
|
|
176
|
+
type: string
|
|
177
|
+
description: Filter objects by key prefix
|
|
178
|
+
example: users/
|
|
179
|
+
- name: limit
|
|
180
|
+
in: query
|
|
181
|
+
required: false
|
|
182
|
+
schema:
|
|
183
|
+
type: integer
|
|
184
|
+
minimum: 1
|
|
185
|
+
maximum: 1000
|
|
186
|
+
default: 100
|
|
187
|
+
- name: offset
|
|
188
|
+
in: query
|
|
189
|
+
required: false
|
|
190
|
+
schema:
|
|
191
|
+
type: integer
|
|
192
|
+
minimum: 0
|
|
193
|
+
default: 0
|
|
194
|
+
responses:
|
|
195
|
+
'200':
|
|
196
|
+
description: List of objects in bucket
|
|
197
|
+
content:
|
|
198
|
+
application/json:
|
|
199
|
+
schema:
|
|
200
|
+
type: object
|
|
201
|
+
properties:
|
|
202
|
+
data:
|
|
203
|
+
type: array
|
|
204
|
+
items:
|
|
205
|
+
$ref: '#/components/schemas/StoredFile'
|
|
206
|
+
pagination:
|
|
207
|
+
type: object
|
|
208
|
+
properties:
|
|
209
|
+
offset:
|
|
210
|
+
type: integer
|
|
211
|
+
example: 0
|
|
212
|
+
limit:
|
|
213
|
+
type: integer
|
|
214
|
+
example: 100
|
|
215
|
+
total:
|
|
216
|
+
type: integer
|
|
217
|
+
example: 2
|
|
218
|
+
nextActions:
|
|
219
|
+
type: string
|
|
220
|
+
example: "You can use PUT /api/storage/buckets/:bucketName/objects/:objectKey to upload with a specific key, or POST /api/storage/buckets/:bucketName/objects to upload with auto-generated key, and GET /api/storage/buckets/:bucketName/objects/:objectKey to download an object."
|
|
221
|
+
example:
|
|
222
|
+
data:
|
|
223
|
+
- bucket: "avatars"
|
|
224
|
+
key: "users/user123.jpg"
|
|
225
|
+
size: 102400
|
|
226
|
+
mimeType: "image/jpeg"
|
|
227
|
+
uploadedAt: "2024-01-15T10:30:00Z"
|
|
228
|
+
url: "/api/storage/buckets/avatars/objects/users/user123.jpg"
|
|
229
|
+
- bucket: "avatars"
|
|
230
|
+
key: "users/user456.png"
|
|
231
|
+
size: 204800
|
|
232
|
+
mimeType: "image/png"
|
|
233
|
+
uploadedAt: "2024-01-16T11:00:00Z"
|
|
234
|
+
url: "/api/storage/buckets/avatars/objects/users/user456.png"
|
|
235
|
+
pagination:
|
|
236
|
+
offset: 0
|
|
237
|
+
limit: 100
|
|
238
|
+
total: 2
|
|
239
|
+
nextActions: "You can use PUT /api/storage/buckets/:bucketName/objects/:objectKey to upload with a specific key, or POST /api/storage/buckets/:bucketName/objects to upload with auto-generated key, and GET /api/storage/buckets/:bucketName/objects/:objectKey to download an object."
|
|
240
|
+
|
|
241
|
+
delete:
|
|
242
|
+
summary: Delete Bucket
|
|
243
|
+
tags:
|
|
244
|
+
- Admin
|
|
245
|
+
security:
|
|
246
|
+
- apiKey: []
|
|
247
|
+
parameters:
|
|
248
|
+
- name: bucketName
|
|
249
|
+
in: path
|
|
250
|
+
required: true
|
|
251
|
+
schema:
|
|
252
|
+
type: string
|
|
253
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
254
|
+
example: avatars
|
|
255
|
+
responses:
|
|
256
|
+
'200':
|
|
257
|
+
description: Bucket deleted successfully
|
|
258
|
+
content:
|
|
259
|
+
application/json:
|
|
260
|
+
schema:
|
|
261
|
+
type: object
|
|
262
|
+
properties:
|
|
263
|
+
message:
|
|
264
|
+
type: string
|
|
265
|
+
example:
|
|
266
|
+
message: "Bucket deleted successfully"
|
|
267
|
+
'404':
|
|
268
|
+
description: Bucket not found
|
|
269
|
+
content:
|
|
270
|
+
application/json:
|
|
271
|
+
schema:
|
|
272
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
273
|
+
example:
|
|
274
|
+
error: "BUCKET_NOT_FOUND"
|
|
275
|
+
message: "Bucket 'nonexistent' does not exist"
|
|
276
|
+
statusCode: 404
|
|
277
|
+
nextActions: "Check bucket name and try again"
|
|
278
|
+
|
|
279
|
+
post:
|
|
280
|
+
summary: Upload Object with Auto-Generated Key
|
|
281
|
+
tags:
|
|
282
|
+
- Client
|
|
283
|
+
security:
|
|
284
|
+
- apiKey: []
|
|
285
|
+
parameters:
|
|
286
|
+
- name: bucketName
|
|
287
|
+
in: path
|
|
288
|
+
required: true
|
|
289
|
+
schema:
|
|
290
|
+
type: string
|
|
291
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
292
|
+
example: avatars
|
|
293
|
+
requestBody:
|
|
294
|
+
required: true
|
|
295
|
+
content:
|
|
296
|
+
multipart/form-data:
|
|
297
|
+
schema:
|
|
298
|
+
type: object
|
|
299
|
+
properties:
|
|
300
|
+
file:
|
|
301
|
+
type: string
|
|
302
|
+
format: binary
|
|
303
|
+
description: File to upload
|
|
304
|
+
required:
|
|
305
|
+
- file
|
|
306
|
+
responses:
|
|
307
|
+
'201':
|
|
308
|
+
description: Object uploaded successfully with auto-generated key
|
|
309
|
+
content:
|
|
310
|
+
application/json:
|
|
311
|
+
schema:
|
|
312
|
+
$ref: '#/components/schemas/StoredFile'
|
|
313
|
+
example:
|
|
314
|
+
bucket: "avatars"
|
|
315
|
+
key: "image-1737546841234-a3f2b1.jpg"
|
|
316
|
+
size: 102400
|
|
317
|
+
mimeType: "image/jpeg"
|
|
318
|
+
uploadedAt: "2024-01-21T10:30:00Z"
|
|
319
|
+
url: "/api/storage/buckets/avatars/objects/image-1737546841234-a3f2b1.jpg"
|
|
320
|
+
'400':
|
|
321
|
+
description: Invalid bucket name or file
|
|
322
|
+
content:
|
|
323
|
+
application/json:
|
|
324
|
+
schema:
|
|
325
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
326
|
+
example:
|
|
327
|
+
error: "INVALID_FILE"
|
|
328
|
+
message: "No file provided in the request"
|
|
329
|
+
statusCode: 400
|
|
330
|
+
nextActions: "Include a file in the multipart form data"
|
|
331
|
+
'404':
|
|
332
|
+
description: Bucket not found
|
|
333
|
+
content:
|
|
334
|
+
application/json:
|
|
335
|
+
schema:
|
|
336
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
337
|
+
example:
|
|
338
|
+
error: "BUCKET_NOT_FOUND"
|
|
339
|
+
message: "Bucket 'nonexistent' does not exist"
|
|
340
|
+
statusCode: 404
|
|
341
|
+
nextActions: "Create the bucket first"
|
|
342
|
+
|
|
343
|
+
/api/storage/buckets/{bucketName}/upload-strategy:
|
|
344
|
+
post:
|
|
345
|
+
summary: Get Upload Strategy (Direct or Presigned URL)
|
|
346
|
+
description: Returns upload strategy based on storage backend (S3 returns presigned URLs, local returns direct upload endpoints)
|
|
347
|
+
tags:
|
|
348
|
+
- Client
|
|
349
|
+
security:
|
|
350
|
+
- apiKey: []
|
|
351
|
+
parameters:
|
|
352
|
+
- name: bucketName
|
|
353
|
+
in: path
|
|
354
|
+
required: true
|
|
355
|
+
schema:
|
|
356
|
+
type: string
|
|
357
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
358
|
+
example: avatars
|
|
359
|
+
requestBody:
|
|
360
|
+
required: true
|
|
361
|
+
content:
|
|
362
|
+
application/json:
|
|
363
|
+
schema:
|
|
364
|
+
type: object
|
|
365
|
+
required:
|
|
366
|
+
- filename
|
|
367
|
+
properties:
|
|
368
|
+
filename:
|
|
369
|
+
type: string
|
|
370
|
+
description: Original filename for generating unique key
|
|
371
|
+
example: profile-photo.jpg
|
|
372
|
+
contentType:
|
|
373
|
+
type: string
|
|
374
|
+
description: MIME type of the file
|
|
375
|
+
example: image/jpeg
|
|
376
|
+
size:
|
|
377
|
+
type: integer
|
|
378
|
+
description: File size in bytes
|
|
379
|
+
example: 102400
|
|
380
|
+
responses:
|
|
381
|
+
'200':
|
|
382
|
+
description: Upload strategy details
|
|
383
|
+
content:
|
|
384
|
+
application/json:
|
|
385
|
+
schema:
|
|
386
|
+
$ref: '#/components/schemas/UploadStrategy'
|
|
387
|
+
examples:
|
|
388
|
+
s3:
|
|
389
|
+
summary: S3 Backend Response
|
|
390
|
+
value:
|
|
391
|
+
method: presigned
|
|
392
|
+
uploadUrl: https://s3-bucket.amazonaws.com/
|
|
393
|
+
fields:
|
|
394
|
+
bucket: my-s3-bucket
|
|
395
|
+
key: app-key/avatars/profile-photo-1234567890-abc123.jpg
|
|
396
|
+
X-Amz-Algorithm: AWS4-HMAC-SHA256
|
|
397
|
+
X-Amz-Credential: AKIA.../20250905/us-east-2/s3/aws4_request
|
|
398
|
+
X-Amz-Date: 20250905T000000Z
|
|
399
|
+
Policy: eyJ...
|
|
400
|
+
X-Amz-Signature: abc123...
|
|
401
|
+
key: profile-photo-1234567890-abc123.jpg
|
|
402
|
+
confirmRequired: true
|
|
403
|
+
confirmUrl: /api/storage/buckets/avatars/objects/profile-photo-1234567890-abc123.jpg/confirm-upload
|
|
404
|
+
expiresAt: "2025-09-05T01:00:00Z"
|
|
405
|
+
local:
|
|
406
|
+
summary: Local Storage Response
|
|
407
|
+
value:
|
|
408
|
+
method: direct
|
|
409
|
+
uploadUrl: /api/storage/buckets/avatars/objects/profile-photo-1234567890-abc123.jpg
|
|
410
|
+
key: profile-photo-1234567890-abc123.jpg
|
|
411
|
+
confirmRequired: false
|
|
412
|
+
'404':
|
|
413
|
+
description: Bucket not found
|
|
414
|
+
content:
|
|
415
|
+
application/json:
|
|
416
|
+
schema:
|
|
417
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
418
|
+
|
|
419
|
+
/api/storage/buckets/{bucketName}/objects/{objectKey}:
|
|
420
|
+
put:
|
|
421
|
+
summary: Upload Object
|
|
422
|
+
tags:
|
|
423
|
+
- Client
|
|
424
|
+
security:
|
|
425
|
+
- apiKey: []
|
|
426
|
+
parameters:
|
|
427
|
+
- name: bucketName
|
|
428
|
+
in: path
|
|
429
|
+
required: true
|
|
430
|
+
schema:
|
|
431
|
+
type: string
|
|
432
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
433
|
+
example: avatars
|
|
434
|
+
- name: objectKey
|
|
435
|
+
in: path
|
|
436
|
+
required: true
|
|
437
|
+
schema:
|
|
438
|
+
type: string
|
|
439
|
+
example: user123.jpg
|
|
440
|
+
description: Object key (can include forward slashes for pseudo-folders)
|
|
441
|
+
requestBody:
|
|
442
|
+
required: true
|
|
443
|
+
content:
|
|
444
|
+
multipart/form-data:
|
|
445
|
+
schema:
|
|
446
|
+
type: object
|
|
447
|
+
properties:
|
|
448
|
+
file:
|
|
449
|
+
type: string
|
|
450
|
+
format: binary
|
|
451
|
+
description: File to upload
|
|
452
|
+
required:
|
|
453
|
+
- file
|
|
454
|
+
responses:
|
|
455
|
+
'201':
|
|
456
|
+
description: Object uploaded successfully
|
|
457
|
+
content:
|
|
458
|
+
application/json:
|
|
459
|
+
schema:
|
|
460
|
+
$ref: '#/components/schemas/StoredFile'
|
|
461
|
+
example:
|
|
462
|
+
bucket: "avatars"
|
|
463
|
+
key: "user123.jpg"
|
|
464
|
+
size: 102400
|
|
465
|
+
mimeType: "image/jpeg"
|
|
466
|
+
uploadedAt: "2024-01-21T10:30:00Z"
|
|
467
|
+
url: "/api/storage/buckets/avatars/objects/user123.jpg"
|
|
468
|
+
'400':
|
|
469
|
+
description: Invalid bucket name, key, or file
|
|
470
|
+
content:
|
|
471
|
+
application/json:
|
|
472
|
+
schema:
|
|
473
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
474
|
+
example:
|
|
475
|
+
error: "INVALID_FILE"
|
|
476
|
+
message: "No file provided in the request"
|
|
477
|
+
statusCode: 400
|
|
478
|
+
nextActions: "Include a file in the multipart form data"
|
|
479
|
+
'404':
|
|
480
|
+
description: Bucket not found
|
|
481
|
+
content:
|
|
482
|
+
application/json:
|
|
483
|
+
schema:
|
|
484
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
485
|
+
example:
|
|
486
|
+
error: "BUCKET_NOT_FOUND"
|
|
487
|
+
message: "Bucket 'nonexistent' does not exist"
|
|
488
|
+
statusCode: 404
|
|
489
|
+
nextActions: "Create the bucket first"
|
|
490
|
+
|
|
491
|
+
get:
|
|
492
|
+
summary: Download Object
|
|
493
|
+
tags:
|
|
494
|
+
- Client
|
|
495
|
+
security:
|
|
496
|
+
- apiKey: []
|
|
497
|
+
parameters:
|
|
498
|
+
- name: bucketName
|
|
499
|
+
in: path
|
|
500
|
+
required: true
|
|
501
|
+
schema:
|
|
502
|
+
type: string
|
|
503
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
504
|
+
example: avatars
|
|
505
|
+
- name: key
|
|
506
|
+
in: path
|
|
507
|
+
required: true
|
|
508
|
+
schema:
|
|
509
|
+
type: string
|
|
510
|
+
example: user123.jpg
|
|
511
|
+
responses:
|
|
512
|
+
'200':
|
|
513
|
+
description: File content
|
|
514
|
+
content:
|
|
515
|
+
'*/*':
|
|
516
|
+
schema:
|
|
517
|
+
type: string
|
|
518
|
+
format: binary
|
|
519
|
+
headers:
|
|
520
|
+
Content-Type:
|
|
521
|
+
schema:
|
|
522
|
+
type: string
|
|
523
|
+
description: MIME type of the file
|
|
524
|
+
Content-Length:
|
|
525
|
+
schema:
|
|
526
|
+
type: integer
|
|
527
|
+
description: Size of the file in bytes
|
|
528
|
+
'404':
|
|
529
|
+
description: Object not found
|
|
530
|
+
content:
|
|
531
|
+
application/json:
|
|
532
|
+
schema:
|
|
533
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
534
|
+
example:
|
|
535
|
+
error: "OBJECT_NOT_FOUND"
|
|
536
|
+
message: "Object 'user123.jpg' not found in bucket 'avatars'"
|
|
537
|
+
statusCode: 404
|
|
538
|
+
nextActions: "Check the bucket and key combination"
|
|
539
|
+
|
|
540
|
+
delete:
|
|
541
|
+
summary: Delete Object
|
|
542
|
+
tags:
|
|
543
|
+
- Client
|
|
544
|
+
security:
|
|
545
|
+
- apiKey: []
|
|
546
|
+
parameters:
|
|
547
|
+
- name: bucketName
|
|
548
|
+
in: path
|
|
549
|
+
required: true
|
|
550
|
+
schema:
|
|
551
|
+
type: string
|
|
552
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
553
|
+
example: avatars
|
|
554
|
+
- name: key
|
|
555
|
+
in: path
|
|
556
|
+
required: true
|
|
557
|
+
schema:
|
|
558
|
+
type: string
|
|
559
|
+
example: user123.jpg
|
|
560
|
+
responses:
|
|
561
|
+
'200':
|
|
562
|
+
description: Object deleted successfully
|
|
563
|
+
content:
|
|
564
|
+
application/json:
|
|
565
|
+
schema:
|
|
566
|
+
type: object
|
|
567
|
+
properties:
|
|
568
|
+
message:
|
|
569
|
+
type: string
|
|
570
|
+
example:
|
|
571
|
+
message: "Object deleted successfully"
|
|
572
|
+
'404':
|
|
573
|
+
description: Object not found
|
|
574
|
+
content:
|
|
575
|
+
application/json:
|
|
576
|
+
schema:
|
|
577
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
578
|
+
example:
|
|
579
|
+
error: "OBJECT_NOT_FOUND"
|
|
580
|
+
message: "Object 'user123.jpg' not found in bucket 'avatars'"
|
|
581
|
+
statusCode: 404
|
|
582
|
+
nextActions: "Check the bucket and key combination"
|
|
583
|
+
|
|
584
|
+
/api/storage/buckets/{bucketName}/objects/{objectKey}/confirm-upload:
|
|
585
|
+
post:
|
|
586
|
+
summary: Confirm Presigned Upload
|
|
587
|
+
description: Confirms that a file was successfully uploaded to S3 using presigned URL
|
|
588
|
+
tags:
|
|
589
|
+
- Client
|
|
590
|
+
security:
|
|
591
|
+
- apiKey: []
|
|
592
|
+
parameters:
|
|
593
|
+
- name: bucketName
|
|
594
|
+
in: path
|
|
595
|
+
required: true
|
|
596
|
+
schema:
|
|
597
|
+
type: string
|
|
598
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
599
|
+
example: avatars
|
|
600
|
+
- name: objectKey
|
|
601
|
+
in: path
|
|
602
|
+
required: true
|
|
603
|
+
schema:
|
|
604
|
+
type: string
|
|
605
|
+
example: profile-photo-1234567890-abc123.jpg
|
|
606
|
+
requestBody:
|
|
607
|
+
required: true
|
|
608
|
+
content:
|
|
609
|
+
application/json:
|
|
610
|
+
schema:
|
|
611
|
+
type: object
|
|
612
|
+
required:
|
|
613
|
+
- size
|
|
614
|
+
properties:
|
|
615
|
+
size:
|
|
616
|
+
type: integer
|
|
617
|
+
description: File size in bytes
|
|
618
|
+
example: 102400
|
|
619
|
+
contentType:
|
|
620
|
+
type: string
|
|
621
|
+
description: MIME type of the file
|
|
622
|
+
example: image/jpeg
|
|
623
|
+
etag:
|
|
624
|
+
type: string
|
|
625
|
+
description: S3 ETag of the uploaded object (optional)
|
|
626
|
+
example: "9bb58f26192e4ba00f01e2e7b136bbd8"
|
|
627
|
+
responses:
|
|
628
|
+
'201':
|
|
629
|
+
description: Upload confirmed successfully
|
|
630
|
+
content:
|
|
631
|
+
application/json:
|
|
632
|
+
schema:
|
|
633
|
+
$ref: '#/components/schemas/StoredFile'
|
|
634
|
+
'404':
|
|
635
|
+
description: Upload not found
|
|
636
|
+
content:
|
|
637
|
+
application/json:
|
|
638
|
+
schema:
|
|
639
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
640
|
+
example:
|
|
641
|
+
error: "UPLOAD_NOT_FOUND"
|
|
642
|
+
message: "Upload not found for key 'profile-photo.jpg' in bucket 'avatars'"
|
|
643
|
+
statusCode: 404
|
|
644
|
+
'409':
|
|
645
|
+
description: Already confirmed
|
|
646
|
+
content:
|
|
647
|
+
application/json:
|
|
648
|
+
schema:
|
|
649
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
650
|
+
example:
|
|
651
|
+
error: "ALREADY_CONFIRMED"
|
|
652
|
+
message: "File 'profile-photo.jpg' already confirmed in bucket 'avatars'"
|
|
653
|
+
statusCode: 409
|
|
654
|
+
|
|
655
|
+
/api/storage/buckets/{bucketName}/objects/{objectKey}/download-strategy:
|
|
656
|
+
post:
|
|
657
|
+
summary: Get Download Strategy (Direct or Presigned URL)
|
|
658
|
+
description: |
|
|
659
|
+
Returns download strategy based on storage backend and bucket visibility.
|
|
660
|
+
- S3 with public bucket: Direct URLs (no presigning, better performance)
|
|
661
|
+
- S3 with private bucket: Presigned URLs with expiration
|
|
662
|
+
- Local storage: Always direct endpoints
|
|
663
|
+
tags:
|
|
664
|
+
- Client
|
|
665
|
+
security:
|
|
666
|
+
- apiKey: []
|
|
667
|
+
parameters:
|
|
668
|
+
- name: bucketName
|
|
669
|
+
in: path
|
|
670
|
+
required: true
|
|
671
|
+
schema:
|
|
672
|
+
type: string
|
|
673
|
+
pattern: '^[a-zA-Z0-9_-]+$'
|
|
674
|
+
example: avatars
|
|
675
|
+
- name: objectKey
|
|
676
|
+
in: path
|
|
677
|
+
required: true
|
|
678
|
+
schema:
|
|
679
|
+
type: string
|
|
680
|
+
example: profile-photo.jpg
|
|
681
|
+
requestBody:
|
|
682
|
+
content:
|
|
683
|
+
application/json:
|
|
684
|
+
schema:
|
|
685
|
+
type: object
|
|
686
|
+
properties:
|
|
687
|
+
expiresIn:
|
|
688
|
+
type: integer
|
|
689
|
+
description: URL expiration time in seconds (default 3600)
|
|
690
|
+
example: 3600
|
|
691
|
+
default: 3600
|
|
692
|
+
responses:
|
|
693
|
+
'200':
|
|
694
|
+
description: Download strategy details
|
|
695
|
+
content:
|
|
696
|
+
application/json:
|
|
697
|
+
schema:
|
|
698
|
+
$ref: '#/components/schemas/DownloadStrategy'
|
|
699
|
+
examples:
|
|
700
|
+
s3-public:
|
|
701
|
+
summary: S3 Public Bucket Response
|
|
702
|
+
value:
|
|
703
|
+
method: direct
|
|
704
|
+
url: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/public-assets/logo.png
|
|
705
|
+
s3-private:
|
|
706
|
+
summary: S3 Private Bucket Response
|
|
707
|
+
value:
|
|
708
|
+
method: presigned
|
|
709
|
+
url: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/avatars/profile.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...
|
|
710
|
+
expiresAt: "2025-09-05T01:00:00Z"
|
|
711
|
+
local:
|
|
712
|
+
summary: Local Storage Response
|
|
713
|
+
value:
|
|
714
|
+
method: direct
|
|
715
|
+
url: /api/storage/buckets/avatars/objects/profile-photo.jpg
|
|
716
|
+
'404':
|
|
717
|
+
description: Object not found
|
|
718
|
+
content:
|
|
719
|
+
application/json:
|
|
720
|
+
schema:
|
|
721
|
+
$ref: '#/components/schemas/ErrorResponse'
|
|
722
|
+
|
|
723
|
+
components:
|
|
724
|
+
securitySchemes:
|
|
725
|
+
apiKey:
|
|
726
|
+
type: apiKey
|
|
727
|
+
in: header
|
|
728
|
+
name: x-api-key
|
|
729
|
+
|
|
730
|
+
schemas:
|
|
731
|
+
StoredFile:
|
|
732
|
+
type: object
|
|
733
|
+
properties:
|
|
734
|
+
bucket:
|
|
735
|
+
type: string
|
|
736
|
+
example: avatars
|
|
737
|
+
description: Name of the bucket containing the object
|
|
738
|
+
key:
|
|
739
|
+
type: string
|
|
740
|
+
example: user123.jpg
|
|
741
|
+
description: Unique key identifying the object within the bucket
|
|
742
|
+
size:
|
|
743
|
+
type: integer
|
|
744
|
+
example: 102400
|
|
745
|
+
description: Size of the file in bytes
|
|
746
|
+
mimeType:
|
|
747
|
+
type: string
|
|
748
|
+
example: image/jpeg
|
|
749
|
+
description: MIME type of the file
|
|
750
|
+
uploadedAt:
|
|
751
|
+
type: string
|
|
752
|
+
format: date-time
|
|
753
|
+
example: "2024-01-15T10:30:00Z"
|
|
754
|
+
description: ISO timestamp when the file was uploaded
|
|
755
|
+
url:
|
|
756
|
+
type: string
|
|
757
|
+
example: "/api/storage/buckets/avatars/objects/user123.jpg"
|
|
758
|
+
description: URL to download the file
|
|
759
|
+
required:
|
|
760
|
+
- bucket
|
|
761
|
+
- key
|
|
762
|
+
- size
|
|
763
|
+
- uploadedAt
|
|
764
|
+
- url
|
|
765
|
+
|
|
766
|
+
Pagination:
|
|
767
|
+
type: object
|
|
768
|
+
properties:
|
|
769
|
+
limit:
|
|
770
|
+
type: integer
|
|
771
|
+
example: 100
|
|
772
|
+
offset:
|
|
773
|
+
type: integer
|
|
774
|
+
example: 0
|
|
775
|
+
total:
|
|
776
|
+
type: integer
|
|
777
|
+
example: 1
|
|
778
|
+
required:
|
|
779
|
+
- limit
|
|
780
|
+
- offset
|
|
781
|
+
- total
|
|
782
|
+
|
|
783
|
+
UploadStrategy:
|
|
784
|
+
type: object
|
|
785
|
+
required:
|
|
786
|
+
- method
|
|
787
|
+
- uploadUrl
|
|
788
|
+
- key
|
|
789
|
+
- confirmRequired
|
|
790
|
+
properties:
|
|
791
|
+
method:
|
|
792
|
+
type: string
|
|
793
|
+
enum: [presigned, direct]
|
|
794
|
+
description: Upload method - presigned for S3, direct for local storage
|
|
795
|
+
example: presigned
|
|
796
|
+
uploadUrl:
|
|
797
|
+
type: string
|
|
798
|
+
description: URL to upload the file to
|
|
799
|
+
example: https://s3-bucket.amazonaws.com/
|
|
800
|
+
fields:
|
|
801
|
+
type: object
|
|
802
|
+
description: Form fields for presigned POST (S3 only)
|
|
803
|
+
additionalProperties: true
|
|
804
|
+
example:
|
|
805
|
+
bucket: my-s3-bucket
|
|
806
|
+
key: app-key/avatars/profile.jpg
|
|
807
|
+
X-Amz-Algorithm: AWS4-HMAC-SHA256
|
|
808
|
+
key:
|
|
809
|
+
type: string
|
|
810
|
+
description: Generated unique key for the file
|
|
811
|
+
example: profile-photo-1234567890-abc123.jpg
|
|
812
|
+
confirmRequired:
|
|
813
|
+
type: boolean
|
|
814
|
+
description: Whether upload confirmation is required
|
|
815
|
+
example: true
|
|
816
|
+
confirmUrl:
|
|
817
|
+
type: string
|
|
818
|
+
description: URL to confirm the upload (if confirmRequired is true)
|
|
819
|
+
example: /api/storage/buckets/avatars/objects/profile.jpg/confirm-upload
|
|
820
|
+
expiresAt:
|
|
821
|
+
type: string
|
|
822
|
+
format: date-time
|
|
823
|
+
description: Expiration time for presigned URL (S3 only)
|
|
824
|
+
example: "2025-09-05T01:00:00Z"
|
|
825
|
+
|
|
826
|
+
DownloadStrategy:
|
|
827
|
+
type: object
|
|
828
|
+
required:
|
|
829
|
+
- method
|
|
830
|
+
- url
|
|
831
|
+
properties:
|
|
832
|
+
method:
|
|
833
|
+
type: string
|
|
834
|
+
enum: [presigned, direct]
|
|
835
|
+
description: |
|
|
836
|
+
Download method:
|
|
837
|
+
- `direct`: Direct URL access (S3 public buckets or local storage)
|
|
838
|
+
- `presigned`: Secure URL with signature and expiration (S3 private buckets)
|
|
839
|
+
example: direct
|
|
840
|
+
url:
|
|
841
|
+
type: string
|
|
842
|
+
description: URL to download the file from
|
|
843
|
+
example: https://s3-bucket.s3.us-east-2.amazonaws.com/app-key/public-assets/logo.png
|
|
844
|
+
expiresAt:
|
|
845
|
+
type: string
|
|
846
|
+
format: date-time
|
|
847
|
+
description: Expiration time for presigned URLs (only present when method is 'presigned')
|
|
848
|
+
example: "2025-09-05T01:00:00Z"
|
|
849
|
+
headers:
|
|
850
|
+
type: object
|
|
851
|
+
description: Optional headers to include in the download request
|
|
852
|
+
additionalProperties: true
|
|
853
|
+
|
|
854
|
+
ErrorResponse:
|
|
855
|
+
type: object
|
|
856
|
+
required:
|
|
857
|
+
- error
|
|
858
|
+
- message
|
|
859
|
+
- statusCode
|
|
860
|
+
properties:
|
|
861
|
+
error:
|
|
862
|
+
type: string
|
|
863
|
+
description: Error code for programmatic handling
|
|
864
|
+
example: "VALIDATION_ERROR"
|
|
865
|
+
message:
|
|
866
|
+
type: string
|
|
867
|
+
description: Human-readable error message
|
|
868
|
+
example: "Invalid request"
|
|
869
|
+
statusCode:
|
|
870
|
+
type: integer
|
|
871
|
+
description: HTTP status code
|
|
872
|
+
example: 400
|
|
873
|
+
nextActions:
|
|
874
|
+
type: string
|
|
875
|
+
description: Suggested action to resolve the error
|
|
876
876
|
example: "Check your request parameters"
|