@aurabase/aurabase-js 0.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/.changeset/config.json +11 -0
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +833 -0
- package/package.json +90 -0
- package/packages/ai/LICENSE +21 -0
- package/packages/ai/README.md +106 -0
- package/packages/ai/dist/index.cjs +229 -0
- package/packages/ai/dist/index.d.cts +139 -0
- package/packages/ai/dist/index.d.ts +139 -0
- package/packages/ai/dist/index.js +226 -0
- package/packages/ai/node_modules/.bin/esbuild +19 -0
- package/packages/ai/node_modules/.bin/tsc +22 -0
- package/packages/ai/node_modules/.bin/tsserver +22 -0
- package/packages/ai/node_modules/.bin/tsup +22 -0
- package/packages/ai/node_modules/.bin/tsup-node +22 -0
- package/packages/ai/node_modules/.bin/vite +22 -0
- package/packages/ai/node_modules/.bin/vitest +22 -0
- package/packages/ai/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/ai/package.json +61 -0
- package/packages/ai/src/AiService.ts +226 -0
- package/packages/ai/src/index.ts +18 -0
- package/packages/ai/src/sse.ts +141 -0
- package/packages/ai/src/types.ts +30 -0
- package/packages/ai/tests/chat-stream.test.ts +151 -0
- package/packages/ai/tests/rag-namespaces.test.ts +54 -0
- package/packages/ai/tests/sse.test.ts +69 -0
- package/packages/ai/tsconfig.json +5 -0
- package/packages/ai/tsup.config.ts +11 -0
- package/packages/aurabase/LICENSE +21 -0
- package/packages/aurabase/README.md +64 -0
- package/packages/aurabase/dist/AuraClient-DAtDbfPB.d.cts +77 -0
- package/packages/aurabase/dist/AuraClient-DAtDbfPB.d.ts +77 -0
- package/packages/aurabase/dist/index.cjs +237 -0
- package/packages/aurabase/dist/index.d.cts +46 -0
- package/packages/aurabase/dist/index.d.ts +46 -0
- package/packages/aurabase/dist/index.js +177 -0
- package/packages/aurabase/dist/ssr.cjs +224 -0
- package/packages/aurabase/dist/ssr.d.cts +65 -0
- package/packages/aurabase/dist/ssr.d.ts +65 -0
- package/packages/aurabase/dist/ssr.js +214 -0
- package/packages/aurabase/node_modules/.bin/esbuild +19 -0
- package/packages/aurabase/node_modules/.bin/tsc +22 -0
- package/packages/aurabase/node_modules/.bin/tsserver +22 -0
- package/packages/aurabase/node_modules/.bin/tsup +22 -0
- package/packages/aurabase/node_modules/.bin/tsup-node +22 -0
- package/packages/aurabase/node_modules/.bin/vite +22 -0
- package/packages/aurabase/node_modules/.bin/vitest +22 -0
- package/packages/aurabase/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/aurabase/package.json +80 -0
- package/packages/aurabase/src/AuraClient.ts +237 -0
- package/packages/aurabase/src/index.ts +152 -0
- package/packages/aurabase/src/ssr.ts +156 -0
- package/packages/aurabase/tests/ai-streaming-rag-e2e.test.ts +82 -0
- package/packages/aurabase/tests/ai.test.ts +111 -0
- package/packages/aurabase/tests/auth-admin.test.ts +515 -0
- package/packages/aurabase/tests/auth-e2e.test.ts +135 -0
- package/packages/aurabase/tests/auth-hardening.test.ts +206 -0
- package/packages/aurabase/tests/auth.test.ts +947 -0
- package/packages/aurabase/tests/database.test.ts +230 -0
- package/packages/aurabase/tests/db-types-e2e.test.ts +217 -0
- package/packages/aurabase/tests/dispose.test.ts +23 -0
- package/packages/aurabase/tests/foreign-token.e2e.test.ts +129 -0
- package/packages/aurabase/tests/functions.test.ts +107 -0
- package/packages/aurabase/tests/integration.test.ts +413 -0
- package/packages/aurabase/tests/live-production-validation.js +241 -0
- package/packages/aurabase/tests/live-sdk-production-validation.js +293 -0
- package/packages/aurabase/tests/mocks.ts +139 -0
- package/packages/aurabase/tests/notifications.test.ts +314 -0
- package/packages/aurabase/tests/observability-backup.test.ts +186 -0
- package/packages/aurabase/tests/observability-hook.test.ts +130 -0
- package/packages/aurabase/tests/production-robustness.test.ts +268 -0
- package/packages/aurabase/tests/public-api-surface.test.ts +53 -0
- package/packages/aurabase/tests/query-builder.test.ts +329 -0
- package/packages/aurabase/tests/readme-smoke-e2e.test.ts +231 -0
- package/packages/aurabase/tests/realtime-filter-e2e.test.ts +344 -0
- package/packages/aurabase/tests/refresh-locks.test.ts +210 -0
- package/packages/aurabase/tests/retry-option.test.ts +17 -0
- package/packages/aurabase/tests/rpc-e2e.test.ts +254 -0
- package/packages/aurabase/tests/rs256-local-e2e.test.ts +114 -0
- package/packages/aurabase/tests/rt-alias-public-e2e.test.ts +235 -0
- package/packages/aurabase/tests/rt-http-broadcast-e2e.test.ts +124 -0
- package/packages/aurabase/tests/service-role-guard.test.ts +99 -0
- package/packages/aurabase/tests/ssr.test.ts +91 -0
- package/packages/aurabase/tests/storage-backend-e2e.test.ts +481 -0
- package/packages/aurabase/tests/storage-sdk-parity-e2e.test.ts +104 -0
- package/packages/aurabase/tests/storage-transform-e2e.test.ts +684 -0
- package/packages/aurabase/tests/storage.test.ts +55 -0
- package/packages/aurabase/tests/types/client-generic.test-d.ts +79 -0
- package/packages/aurabase/tests/types/docs-snippets.test-d.ts +571 -0
- package/packages/aurabase/tests/types/error-code.test-d.ts +53 -0
- package/packages/aurabase/tsconfig.json +5 -0
- package/packages/aurabase/tsconfig.test-d.json +5 -0
- package/packages/aurabase/tsup.config.ts +11 -0
- package/packages/aurabase/vitest.config.ts +16 -0
- package/packages/aurabase/vitest.e2e.config.ts +9 -0
- package/packages/auth/LICENSE +21 -0
- package/packages/auth/README.md +215 -0
- package/packages/auth/dist/index.cjs +1175 -0
- package/packages/auth/dist/index.d.cts +397 -0
- package/packages/auth/dist/index.d.ts +397 -0
- package/packages/auth/dist/index.js +1170 -0
- package/packages/auth/node_modules/.bin/esbuild +19 -0
- package/packages/auth/node_modules/.bin/tsc +22 -0
- package/packages/auth/node_modules/.bin/tsserver +22 -0
- package/packages/auth/node_modules/.bin/tsup +22 -0
- package/packages/auth/node_modules/.bin/tsup-node +22 -0
- package/packages/auth/node_modules/.bin/vite +22 -0
- package/packages/auth/node_modules/.bin/vitest +22 -0
- package/packages/auth/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/auth/package.json +61 -0
- package/packages/auth/src/AuthAdminService.ts +149 -0
- package/packages/auth/src/AuthService.ts +1166 -0
- package/packages/auth/src/SessionManager.ts +92 -0
- package/packages/auth/src/index.ts +17 -0
- package/packages/auth/src/jwks.ts +337 -0
- package/packages/auth/src/pkce.ts +27 -0
- package/packages/auth/src/types.ts +89 -0
- package/packages/auth/tests/auth-lifecycle.test.ts +149 -0
- package/packages/auth/tests/detect-session.test.ts +361 -0
- package/packages/auth/tests/getclaims.test.ts +780 -0
- package/packages/auth/tests/is-mfa-challenge.test.ts +27 -0
- package/packages/auth/tests/password-recovery.test.ts +124 -0
- package/packages/auth/tests/pkce.test.ts +192 -0
- package/packages/auth/tests/session-manager.test.ts +103 -0
- package/packages/auth/tests/set-session.test.ts +139 -0
- package/packages/auth/tests/verify-otp.test.ts +153 -0
- package/packages/auth/tsconfig.json +5 -0
- package/packages/auth/tsup.config.ts +11 -0
- package/packages/core/LICENSE +21 -0
- package/packages/core/README.md +132 -0
- package/packages/core/dist/index.cjs +695 -0
- package/packages/core/dist/index.d.cts +1137 -0
- package/packages/core/dist/index.d.ts +1137 -0
- package/packages/core/dist/index.js +673 -0
- package/packages/core/node_modules/.bin/esbuild +22 -0
- package/packages/core/node_modules/.bin/tsc +22 -0
- package/packages/core/node_modules/.bin/tsserver +22 -0
- package/packages/core/node_modules/.bin/tsup +22 -0
- package/packages/core/node_modules/.bin/tsup-node +22 -0
- package/packages/core/node_modules/.bin/vite +22 -0
- package/packages/core/node_modules/.bin/vitest +22 -0
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/core/package.json +57 -0
- package/packages/core/src/AuraError.ts +89 -0
- package/packages/core/src/BaseService.ts +44 -0
- package/packages/core/src/client.ts +34 -0
- package/packages/core/src/cookie-utils.ts +42 -0
- package/packages/core/src/fetch.ts +435 -0
- package/packages/core/src/index.ts +22 -0
- package/packages/core/src/retry.ts +63 -0
- package/packages/core/src/serialize.ts +6 -0
- package/packages/core/src/stores/BaseAuthStore.ts +164 -0
- package/packages/core/src/stores/LocalAuthStore.ts +199 -0
- package/packages/core/src/types.ts +1042 -0
- package/packages/core/tests/auth-store.test.ts +300 -0
- package/packages/core/tests/error-code.test.ts +61 -0
- package/packages/core/tests/error.test.ts +24 -0
- package/packages/core/tests/fetch.test.ts +286 -0
- package/packages/core/tests/mocks.ts +139 -0
- package/packages/core/tests/observability.test.ts +86 -0
- package/packages/core/tests/refresh-hardening.test.ts +164 -0
- package/packages/core/tests/refresh-observability.test.ts +111 -0
- package/packages/core/tests/retry.test.ts +106 -0
- package/packages/core/tests/serialize.test.ts +12 -0
- package/packages/core/tests/timeout.test.ts +79 -0
- package/packages/core/tsconfig.json +5 -0
- package/packages/core/tsup.config.ts +11 -0
- package/packages/db/LICENSE +21 -0
- package/packages/db/README.md +152 -0
- package/packages/db/VENDORED.md +93 -0
- package/packages/db/dist/index.cjs +544 -0
- package/packages/db/dist/index.d.cts +1111 -0
- package/packages/db/dist/index.d.ts +1111 -0
- package/packages/db/dist/index.js +541 -0
- package/packages/db/node_modules/.bin/esbuild +19 -0
- package/packages/db/node_modules/.bin/tsc +22 -0
- package/packages/db/node_modules/.bin/tsserver +22 -0
- package/packages/db/node_modules/.bin/tsup +22 -0
- package/packages/db/node_modules/.bin/tsup-node +22 -0
- package/packages/db/node_modules/.bin/vite +22 -0
- package/packages/db/node_modules/.bin/vitest +22 -0
- package/packages/db/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/db/package.json +62 -0
- package/packages/db/src/DatabaseService.ts +170 -0
- package/packages/db/src/QueryBuilder.ts +830 -0
- package/packages/db/src/index.ts +2 -0
- package/packages/db/src/pgrst-types/common/common.ts +86 -0
- package/packages/db/src/pgrst-types/common/rpc.ts +151 -0
- package/packages/db/src/pgrst-types/feature-flags.ts +20 -0
- package/packages/db/src/pgrst-types/types.ts +134 -0
- package/packages/db/src/select-query-parser/parser.ts +479 -0
- package/packages/db/src/select-query-parser/result.ts +553 -0
- package/packages/db/src/select-query-parser/types.ts +132 -0
- package/packages/db/src/select-query-parser/utils.ts +707 -0
- package/packages/db/tests/filters.test.ts +81 -0
- package/packages/db/tests/mutations-filtered.e2e.test.ts +132 -0
- package/packages/db/tests/mutations-filtered.test.ts +188 -0
- package/packages/db/tests/order.test.ts +45 -0
- package/packages/db/tests/rpc.test.ts +41 -0
- package/packages/db/tests/scale/build-large-schema.ts +94 -0
- package/packages/db/tests/scale/scale-compile.test.ts +167 -0
- package/packages/db/tests/schema.test.ts +77 -0
- package/packages/db/tests/single-accept.e2e.test.ts +123 -0
- package/packages/db/tests/single.test.ts +211 -0
- package/packages/db/tests/types/filters.test-d.ts +52 -0
- package/packages/db/tests/types/fixtures.ts +40 -0
- package/packages/db/tests/types/from-views.test-d.ts +18 -0
- package/packages/db/tests/types/mutations.test-d.ts +23 -0
- package/packages/db/tests/types/rpc.test-d.ts +60 -0
- package/packages/db/tests/types/schema-shape.test-d.ts +8 -0
- package/packages/db/tests/types/select-inference.test-d.ts +38 -0
- package/packages/db/tests/vendored/fixtures.ts +83 -0
- package/packages/db/tests/vendored/get-result.test-d.ts +75 -0
- package/packages/db/tsconfig.json +5 -0
- package/packages/db/tsconfig.test-d.json +5 -0
- package/packages/db/tsup.config.ts +11 -0
- package/packages/db/vitest.config.ts +8 -0
- package/packages/functions/LICENSE +21 -0
- package/packages/functions/README.md +96 -0
- package/packages/functions/dist/index.cjs +173 -0
- package/packages/functions/dist/index.d.cts +81 -0
- package/packages/functions/dist/index.d.ts +81 -0
- package/packages/functions/dist/index.js +168 -0
- package/packages/functions/node_modules/.bin/esbuild +19 -0
- package/packages/functions/node_modules/.bin/tsc +22 -0
- package/packages/functions/node_modules/.bin/tsserver +22 -0
- package/packages/functions/node_modules/.bin/tsup +22 -0
- package/packages/functions/node_modules/.bin/tsup-node +22 -0
- package/packages/functions/node_modules/.bin/vite +22 -0
- package/packages/functions/node_modules/.bin/vitest +22 -0
- package/packages/functions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/functions/package.json +60 -0
- package/packages/functions/src/FunctionsService.ts +188 -0
- package/packages/functions/src/errors.ts +70 -0
- package/packages/functions/src/index.ts +6 -0
- package/packages/functions/tests/invoke.test.ts +97 -0
- package/packages/functions/tests/response-type-errors.test.ts +135 -0
- package/packages/functions/tsconfig.json +5 -0
- package/packages/functions/tsup.config.ts +11 -0
- package/packages/gen/LICENSE +21 -0
- package/packages/gen/README.md +84 -0
- package/packages/gen/dist/cli.cjs +334 -0
- package/packages/gen/dist/cli.d.cts +1 -0
- package/packages/gen/dist/cli.d.ts +1 -0
- package/packages/gen/dist/cli.js +332 -0
- package/packages/gen/dist/index.cjs +257 -0
- package/packages/gen/dist/index.d.cts +12 -0
- package/packages/gen/dist/index.d.ts +12 -0
- package/packages/gen/dist/index.js +255 -0
- package/packages/gen/node_modules/.bin/esbuild +19 -0
- package/packages/gen/node_modules/.bin/tsc +22 -0
- package/packages/gen/node_modules/.bin/tsserver +22 -0
- package/packages/gen/node_modules/.bin/tsup +22 -0
- package/packages/gen/node_modules/.bin/tsup-node +22 -0
- package/packages/gen/node_modules/.bin/vite +22 -0
- package/packages/gen/node_modules/.bin/vitest +22 -0
- package/packages/gen/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/gen/package.json +66 -0
- package/packages/gen/src/cli.ts +67 -0
- package/packages/gen/src/generate.ts +0 -0
- package/packages/gen/src/index.ts +2 -0
- package/packages/gen/tests/compile.test.ts +213 -0
- package/packages/gen/tests/e2e.test.ts +130 -0
- package/packages/gen/tests/generate.test.ts +396 -0
- package/packages/gen/tsconfig.json +5 -0
- package/packages/gen/tsup.config.ts +11 -0
- package/packages/notifications/LICENSE +21 -0
- package/packages/notifications/README.md +134 -0
- package/packages/notifications/dist/index.cjs +128 -0
- package/packages/notifications/dist/index.d.cts +81 -0
- package/packages/notifications/dist/index.d.ts +81 -0
- package/packages/notifications/dist/index.js +125 -0
- package/packages/notifications/node_modules/.bin/esbuild +19 -0
- package/packages/notifications/node_modules/.bin/tsc +22 -0
- package/packages/notifications/node_modules/.bin/tsserver +22 -0
- package/packages/notifications/node_modules/.bin/tsup +22 -0
- package/packages/notifications/node_modules/.bin/tsup-node +22 -0
- package/packages/notifications/node_modules/.bin/vite +22 -0
- package/packages/notifications/node_modules/.bin/vitest +22 -0
- package/packages/notifications/package.json +60 -0
- package/packages/notifications/src/NotificationsService.ts +230 -0
- package/packages/notifications/src/index.ts +19 -0
- package/packages/notifications/tsconfig.json +5 -0
- package/packages/notifications/tsup.config.ts +11 -0
- package/packages/realtime/LICENSE +21 -0
- package/packages/realtime/README.md +183 -0
- package/packages/realtime/dist/index.cjs +977 -0
- package/packages/realtime/dist/index.d.cts +259 -0
- package/packages/realtime/dist/index.d.ts +259 -0
- package/packages/realtime/dist/index.js +973 -0
- package/packages/realtime/node_modules/.bin/esbuild +19 -0
- package/packages/realtime/node_modules/.bin/tsc +22 -0
- package/packages/realtime/node_modules/.bin/tsserver +22 -0
- package/packages/realtime/node_modules/.bin/tsup +22 -0
- package/packages/realtime/node_modules/.bin/tsup-node +22 -0
- package/packages/realtime/node_modules/.bin/vite +22 -0
- package/packages/realtime/node_modules/.bin/vitest +22 -0
- package/packages/realtime/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/realtime/package.json +60 -0
- package/packages/realtime/src/AuraChannel.ts +485 -0
- package/packages/realtime/src/HeartbeatManager.ts +73 -0
- package/packages/realtime/src/RealtimeService.ts +505 -0
- package/packages/realtime/src/columnFilter.ts +301 -0
- package/packages/realtime/src/index.ts +4 -0
- package/packages/realtime/tests/ack-routing.test.ts +81 -0
- package/packages/realtime/tests/column-filter.test.ts +144 -0
- package/packages/realtime/tests/dispatch.test.ts +191 -0
- package/packages/realtime/tests/heartbeat.test.ts +67 -0
- package/packages/realtime/tests/http-broadcast.test.ts +68 -0
- package/packages/realtime/tests/realtime-token.test.ts +43 -0
- package/packages/realtime/tests/reconnect-race.test.ts +149 -0
- package/packages/realtime/tests/ref-id.test.ts +34 -0
- package/packages/realtime/tests/set-auth.test.ts +70 -0
- package/packages/realtime/tsconfig.json +5 -0
- package/packages/realtime/tsup.config.ts +11 -0
- package/packages/storage/LICENSE +21 -0
- package/packages/storage/README.md +141 -0
- package/packages/storage/dist/index.cjs +333 -0
- package/packages/storage/dist/index.d.cts +185 -0
- package/packages/storage/dist/index.d.ts +185 -0
- package/packages/storage/dist/index.js +329 -0
- package/packages/storage/node_modules/.bin/esbuild +19 -0
- package/packages/storage/node_modules/.bin/tsc +22 -0
- package/packages/storage/node_modules/.bin/tsserver +22 -0
- package/packages/storage/node_modules/.bin/tsup +22 -0
- package/packages/storage/node_modules/.bin/tsup-node +22 -0
- package/packages/storage/node_modules/.bin/vite +22 -0
- package/packages/storage/node_modules/.bin/vitest +22 -0
- package/packages/storage/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/storage/package.json +60 -0
- package/packages/storage/src/DownloadBuilder.ts +60 -0
- package/packages/storage/src/StorageService.ts +323 -0
- package/packages/storage/src/index.ts +2 -0
- package/packages/storage/src/path.ts +35 -0
- package/packages/storage/src/transform.ts +15 -0
- package/packages/storage/tests/download.test.ts +64 -0
- package/packages/storage/tests/parity.test.ts +154 -0
- package/packages/storage/tests/path.test.ts +87 -0
- package/packages/storage/tests/transform.test.ts +79 -0
- package/packages/storage/tsconfig.json +5 -0
- package/packages/storage/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +24 -0
- package/tsconfig.base.json +15 -0
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { generateDatabaseTypes } from '../src/generate'
|
|
3
|
+
import type { SchemaTable, SchemaFunction } from '@aurabase/core'
|
|
4
|
+
|
|
5
|
+
function col(name: string, col_type: unknown, extra: Partial<{ nullable: boolean; unique: boolean; default_val: string | null; references: { table: string; column: string } | null }> = {}) {
|
|
6
|
+
return { name, col_type: col_type as string, nullable: false, unique: false, default_val: null, references: null, ...extra }
|
|
7
|
+
}
|
|
8
|
+
function table(name: string, columns: ReturnType<typeof col>[], extra: Partial<SchemaTable> = {}): SchemaTable {
|
|
9
|
+
return { name, columns, indexes: [], rls_enabled: false, realtime_enabled: false, ...extra }
|
|
10
|
+
}
|
|
11
|
+
function fn(name: string, args: SchemaFunction['args'], returns: string, is_set_returning = false): SchemaFunction {
|
|
12
|
+
return { name, args, returns, is_set_returning }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe('generateDatabaseTypes — Row', () => {
|
|
16
|
+
it('émet une propriété Row par colonne, nullable → | null', () => {
|
|
17
|
+
const out = generateDatabaseTypes([
|
|
18
|
+
table('users', [col('id', 'uuid'), col('email', 'text'), col('bio', 'text', { nullable: true })]),
|
|
19
|
+
])
|
|
20
|
+
expect(out).toContain('users: {')
|
|
21
|
+
expect(out).toContain('id: string')
|
|
22
|
+
expect(out).toContain('email: string')
|
|
23
|
+
expect(out).toContain('bio: string | null')
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('generateDatabaseTypes — mapping des types', () => {
|
|
28
|
+
it('mappe chaque type pg vers le bon type TS', () => {
|
|
29
|
+
const out = generateDatabaseTypes([
|
|
30
|
+
table('t', [
|
|
31
|
+
col('a_text', 'text'), col('a_uuid', 'uuid'), col('a_ts', 'timestamp'),
|
|
32
|
+
col('a_date', 'date'), col('a_time', 'time'), col('a_bytea', 'bytea'),
|
|
33
|
+
col('a_numeric', 'numeric'), col('a_int', 'int'), col('a_bigint', 'bigint'),
|
|
34
|
+
col('a_float', 'float'), col('a_bool', 'bool'), col('a_json', 'json'),
|
|
35
|
+
col('a_jsonb', 'jsonb'),
|
|
36
|
+
col('a_arr', { array: 'text' }), col('a_vec', { vector: 1536 }),
|
|
37
|
+
]),
|
|
38
|
+
])
|
|
39
|
+
expect(out).toContain('a_text: string')
|
|
40
|
+
expect(out).toContain('a_numeric: string') // NUMERIC = string (précision), jamais number
|
|
41
|
+
expect(out).toContain('a_int: number')
|
|
42
|
+
expect(out).toContain('a_bigint: number')
|
|
43
|
+
expect(out).toContain('a_float: number')
|
|
44
|
+
expect(out).toContain('a_bool: boolean')
|
|
45
|
+
expect(out).toContain('a_json: Json')
|
|
46
|
+
expect(out).toContain('a_jsonb: Json')
|
|
47
|
+
expect(out).toContain('a_arr: string[]') // C2 : array typé (plus `unknown[]`)
|
|
48
|
+
expect(out).toContain('a_vec: number[]')
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('C2 — arrays typés récursifs : {array:int} → number[], {array:{array:text}} → string[][]', () => {
|
|
52
|
+
const out = generateDatabaseTypes([
|
|
53
|
+
table('t', [
|
|
54
|
+
col('ints', { array: 'int' }),
|
|
55
|
+
col('nested', { array: { array: 'text' } }),
|
|
56
|
+
col('bools', { array: 'bool' }),
|
|
57
|
+
]),
|
|
58
|
+
])
|
|
59
|
+
expect(out).toContain('ints: number[]')
|
|
60
|
+
expect(out).toContain('nested: string[][]')
|
|
61
|
+
expect(out).toContain('bools: boolean[]')
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
describe('generateDatabaseTypes — Insert/Update', () => {
|
|
66
|
+
it('Insert : optionnel si nullable / default / colonne auto ; requis sinon', () => {
|
|
67
|
+
const out = generateDatabaseTypes([
|
|
68
|
+
table('posts', [
|
|
69
|
+
col('id', 'uuid', { default_val: 'gen_random_uuid()' }),
|
|
70
|
+
col('title', 'text'), // requis
|
|
71
|
+
col('subtitle', 'text', { nullable: true }), // optionnel (nullable)
|
|
72
|
+
col('views', 'int', { default_val: '0' }), // optionnel (default)
|
|
73
|
+
col('created_at', 'timestamp'), // optionnel (auto)
|
|
74
|
+
]),
|
|
75
|
+
])
|
|
76
|
+
const insert = out.slice(out.indexOf('Insert: {'), out.indexOf('Update: {'))
|
|
77
|
+
expect(insert).toContain('id?: string')
|
|
78
|
+
expect(insert).toContain('title: string') // requis (pas de ?)
|
|
79
|
+
expect(insert).toContain('subtitle?: string | null')
|
|
80
|
+
expect(insert).toContain('views?: number')
|
|
81
|
+
expect(insert).toContain('created_at?: string')
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('Update : toutes les colonnes optionnelles', () => {
|
|
85
|
+
const out = generateDatabaseTypes([table('posts', [col('id', 'uuid'), col('title', 'text')])])
|
|
86
|
+
const update = out.slice(out.indexOf('Update: {'))
|
|
87
|
+
expect(update).toContain('id?: string')
|
|
88
|
+
expect(update).toContain('title?: string')
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('generateDatabaseTypes — Relationships', () => {
|
|
93
|
+
it('table sans FK → Relationships: []', () => {
|
|
94
|
+
const out = generateDatabaseTypes([table('users', [col('id', 'uuid')])])
|
|
95
|
+
expect(out).toContain('Relationships: []')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('FK → tuple avec foreignKeyName synthétisé, isOneToOne selon unique/PK', () => {
|
|
99
|
+
const out = generateDatabaseTypes([
|
|
100
|
+
table('posts', [
|
|
101
|
+
col('id', 'uuid'),
|
|
102
|
+
col('author_id', 'uuid', { references: { table: 'users', column: 'id' } }),
|
|
103
|
+
col('slug', 'text', { unique: true, references: { table: 'seo', column: 'slug' } }),
|
|
104
|
+
], { primary_key: 'id' }),
|
|
105
|
+
])
|
|
106
|
+
expect(out).toContain("foreignKeyName: 'posts_author_id_fkey'")
|
|
107
|
+
expect(out).toContain("columns: ['author_id']")
|
|
108
|
+
expect(out).toContain("referencedRelation: 'users'")
|
|
109
|
+
expect(out).toContain("referencedColumns: ['id']")
|
|
110
|
+
// author_id : ni unique ni PK → false
|
|
111
|
+
expect(out).toMatch(/author_id_fkey'[^}]*?isOneToOne: false/)
|
|
112
|
+
// slug : unique → true
|
|
113
|
+
expect(out).toMatch(/slug_fkey'[^}]*?isOneToOne: true/)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('utilise references.constraint_name si présent', () => {
|
|
117
|
+
const out = generateDatabaseTypes([
|
|
118
|
+
table('posts', [col('author_id', 'uuid', { references: { table: 'users', column: 'id', constraint_name: 'fk_custom' } as unknown as { table: string; column: string } })]),
|
|
119
|
+
])
|
|
120
|
+
expect(out).toContain("foreignKeyName: 'fk_custom'")
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('isOneToOne true via primary_key même sans unique', () => {
|
|
124
|
+
const out = generateDatabaseTypes([
|
|
125
|
+
table('profiles', [
|
|
126
|
+
col('id', 'uuid', { references: { table: 'users', column: 'id' } }),
|
|
127
|
+
], { primary_key: 'id' }),
|
|
128
|
+
])
|
|
129
|
+
expect(out).toMatch(/profiles_id_fkey'[^}]*?isOneToOne: true/)
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe('generateDatabaseTypes — Functions', () => {
|
|
134
|
+
it('aucune fonction → Functions: Record<string, never>', () => {
|
|
135
|
+
const out = generateDatabaseTypes([table('users', [col('id', 'uuid')])])
|
|
136
|
+
expect(out).toContain('Functions: Record<string, never>')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('fonction scalaire (add(a int, b int) → int) : Args + Returns', () => {
|
|
140
|
+
const out = generateDatabaseTypes([], {
|
|
141
|
+
functions: [fn('add', [
|
|
142
|
+
{ name: 'a', data_type: 'int4', mode: 'IN' },
|
|
143
|
+
{ name: 'b', data_type: 'int4', mode: 'IN' },
|
|
144
|
+
], 'int4')],
|
|
145
|
+
})
|
|
146
|
+
expect(out).toContain('add: {')
|
|
147
|
+
const block = out.slice(out.indexOf('add: {'), out.indexOf('add: {') + 300)
|
|
148
|
+
expect(block).toMatch(/Args:\s*{\s*a: number;\s*b: number\s*}/)
|
|
149
|
+
expect(block).toContain('Returns: number')
|
|
150
|
+
expect(block).not.toContain('SetofOptions')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('fonction sans argument → Args: Record<string, never>', () => {
|
|
154
|
+
const out = generateDatabaseTypes([], { functions: [fn('now_utc', [], 'timestamp')] })
|
|
155
|
+
const block = out.slice(out.indexOf('now_utc: {'))
|
|
156
|
+
expect(block).toContain('Args: Record<string, never>')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('fonction SETOF (table-returning) : Returns tableau + SetofOptions', () => {
|
|
160
|
+
const out = generateDatabaseTypes([], {
|
|
161
|
+
functions: [fn('list_things', [], 'record', true)],
|
|
162
|
+
})
|
|
163
|
+
const block = out.slice(out.indexOf('list_things: {'), out.indexOf('list_things: {') + 400)
|
|
164
|
+
expect(block).toContain('Returns: Record<string, unknown>[]')
|
|
165
|
+
expect(block).toContain('SetofOptions: {')
|
|
166
|
+
expect(block).toContain('isSetofReturn: true')
|
|
167
|
+
expect(block).toContain("to: 'list_things'")
|
|
168
|
+
expect(block).toContain("from: '*'")
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('GEN-M1 — overloads (même nom) fusionnés en UNE clé, Args/Returns en union', () => {
|
|
172
|
+
const out = generateDatabaseTypes([], {
|
|
173
|
+
functions: [
|
|
174
|
+
fn('add', [{ name: 'a', data_type: 'int4', mode: 'IN' }, { name: 'b', data_type: 'int4', mode: 'IN' }], 'int4'),
|
|
175
|
+
fn('add', [{ name: 'a', data_type: 'text', mode: 'IN' }, { name: 'b', data_type: 'text', mode: 'IN' }], 'text'),
|
|
176
|
+
],
|
|
177
|
+
})
|
|
178
|
+
// Une seule clé `add:` (pas de duplicate identifier TS2300).
|
|
179
|
+
expect(out.match(/add: {/g)).toHaveLength(1)
|
|
180
|
+
const block = out.slice(out.indexOf('add: {'), out.indexOf('add: {') + 300)
|
|
181
|
+
expect(block).toContain('Args: { a: number; b: number } | { a: string; b: string }')
|
|
182
|
+
expect(block).toContain('Returns: number | string')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('GEN-M1 — overloads : membres identiques dédupliqués (Args unique)', () => {
|
|
186
|
+
const out = generateDatabaseTypes([], {
|
|
187
|
+
functions: [
|
|
188
|
+
fn('f', [{ name: 'x', data_type: 'int4', mode: 'IN' }], 'int4'),
|
|
189
|
+
fn('f', [{ name: 'x', data_type: 'int4', mode: 'IN' }], 'text'), // même Args, Returns diff
|
|
190
|
+
],
|
|
191
|
+
})
|
|
192
|
+
const block = out.slice(out.indexOf('f: {'), out.indexOf('f: {') + 200)
|
|
193
|
+
expect(block).toContain('Args: { x: number }') // pas `| { x: number }` dupliqué
|
|
194
|
+
expect(block).toContain('Returns: number | string')
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it('sortie valide TypeScript (satisfait GenericSchema[\'Functions\'])', () => {
|
|
198
|
+
const out = generateDatabaseTypes([], {
|
|
199
|
+
functions: [
|
|
200
|
+
fn('add', [{ name: 'a', data_type: 'int4', mode: 'IN' }, { name: 'b', data_type: 'int4', mode: 'IN' }], 'int4'),
|
|
201
|
+
fn('list_things', [], 'record', true),
|
|
202
|
+
],
|
|
203
|
+
})
|
|
204
|
+
expect(out).toContain('export interface Database {')
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
describe('generateDatabaseTypes — SETOF <table> : SetofOptions.to résolu (P4)', () => {
|
|
209
|
+
it('RETURNS SETOF users → to: "users" (table connue)', () => {
|
|
210
|
+
const out = generateDatabaseTypes(
|
|
211
|
+
[table('users', [col('id', 'uuid'), col('email', 'text')])],
|
|
212
|
+
{ functions: [fn('list_users', [], 'users', true)] },
|
|
213
|
+
)
|
|
214
|
+
const block = out.slice(out.indexOf('list_users: {'), out.indexOf('list_users: {') + 400)
|
|
215
|
+
expect(block).toContain('SetofOptions: {')
|
|
216
|
+
expect(block).toContain('isSetofReturn: true')
|
|
217
|
+
expect(block).toContain("to: 'users'")
|
|
218
|
+
expect(block).toContain("from: '*'")
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('RETURNS SETOF v_active (vue) → to: "v_active"', () => {
|
|
222
|
+
const out = generateDatabaseTypes([], {
|
|
223
|
+
views: [table('v_active', [col('id', 'uuid')])],
|
|
224
|
+
functions: [fn('active_rows', [], 'v_active', true)],
|
|
225
|
+
})
|
|
226
|
+
const block = out.slice(out.indexOf('active_rows: {'), out.indexOf('active_rows: {') + 400)
|
|
227
|
+
expect(block).toContain("to: 'v_active'")
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('RETURNS record → placeholder to: "<nom_fonction>" (aucune relation)', () => {
|
|
231
|
+
const out = generateDatabaseTypes([], { functions: [fn('list_things', [], 'record', true)] })
|
|
232
|
+
const block = out.slice(out.indexOf('list_things: {'), out.indexOf('list_things: {') + 400)
|
|
233
|
+
expect(block).toContain("to: 'list_things'")
|
|
234
|
+
expect(block).toContain('Returns: Record<string, unknown>[]')
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('returns matche un nom hors relations (type non-relation) → placeholder', () => {
|
|
238
|
+
// `mytype` n'est ni une table ni une vue fournie → repli sur le nom de la fonction.
|
|
239
|
+
const out = generateDatabaseTypes(
|
|
240
|
+
[table('users', [col('id', 'uuid')])],
|
|
241
|
+
{ functions: [fn('weird', [], 'mytype', true)] },
|
|
242
|
+
)
|
|
243
|
+
const block = out.slice(out.indexOf('weird: {'), out.indexOf('weird: {') + 400)
|
|
244
|
+
expect(block).toContain("to: 'weird'")
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('fonction scalaire → pas de SetofOptions (inchangé)', () => {
|
|
248
|
+
const out = generateDatabaseTypes(
|
|
249
|
+
[table('users', [col('id', 'uuid')])],
|
|
250
|
+
{ functions: [fn('count_users', [], 'int4', false)] },
|
|
251
|
+
)
|
|
252
|
+
const block = out.slice(out.indexOf('count_users: {'), out.indexOf('count_users: {') + 200)
|
|
253
|
+
expect(block).not.toContain('SetofOptions')
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
it('overloads set-returning même nom → SetofOptions omis (cible ambiguë)', () => {
|
|
257
|
+
const out = generateDatabaseTypes(
|
|
258
|
+
[table('users', [col('id', 'uuid')])],
|
|
259
|
+
{
|
|
260
|
+
functions: [
|
|
261
|
+
fn('search', [{ name: 'q', data_type: 'text', mode: 'IN' }], 'users', true),
|
|
262
|
+
fn('search', [{ name: 'q', data_type: 'int4', mode: 'IN' }], 'users', true),
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
)
|
|
266
|
+
const block = out.slice(out.indexOf('search: {'), out.indexOf('search: {') + 400)
|
|
267
|
+
expect(block).not.toContain('SetofOptions')
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('generateDatabaseTypes — FK composites (C3)', () => {
|
|
272
|
+
it('groupe 2 colonnes de même constraint_name → UNE relationship multi-colonnes', () => {
|
|
273
|
+
const out = generateDatabaseTypes([
|
|
274
|
+
table('order_items', [
|
|
275
|
+
col('order_tenant', 'uuid', { references: { table: 'orders', column: 'tenant', constraint_name: 'fk_order' } as unknown as { table: string; column: string } }),
|
|
276
|
+
col('order_id', 'uuid', { references: { table: 'orders', column: 'id', constraint_name: 'fk_order' } as unknown as { table: string; column: string } }),
|
|
277
|
+
]),
|
|
278
|
+
])
|
|
279
|
+
expect(out).toContain("foreignKeyName: 'fk_order'")
|
|
280
|
+
expect(out).toContain("columns: ['order_tenant', 'order_id']")
|
|
281
|
+
expect(out).toContain("referencedColumns: ['tenant', 'id']")
|
|
282
|
+
// Une seule entrée : la relationship n'apparaît qu'une fois.
|
|
283
|
+
expect(out.match(/foreignKeyName: 'fk_order'/g)).toHaveLength(1)
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it("n'agrège PAS deux FK anonymes (constraint_name absent) — 2 entrées distinctes", () => {
|
|
287
|
+
const out = generateDatabaseTypes([
|
|
288
|
+
table('t', [
|
|
289
|
+
col('a_id', 'uuid', { references: { table: 'a', column: 'id' } }),
|
|
290
|
+
col('b_id', 'uuid', { references: { table: 'b', column: 'id' } }),
|
|
291
|
+
]),
|
|
292
|
+
])
|
|
293
|
+
expect(out).toContain("columns: ['a_id']")
|
|
294
|
+
expect(out).toContain("columns: ['b_id']")
|
|
295
|
+
expect(out).toContain("foreignKeyName: 't_a_id_fkey'")
|
|
296
|
+
expect(out).toContain("foreignKeyName: 't_b_id_fkey'")
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
describe('generateDatabaseTypes — Enums (C5)', () => {
|
|
301
|
+
it('émet le bloc Enums:{mood: union} et type les colonnes {enum}', () => {
|
|
302
|
+
const out = generateDatabaseTypes(
|
|
303
|
+
[table('users', [col('id', 'uuid'), col('mood', { enum: 'mood' })])],
|
|
304
|
+
{ enums: [{ name: 'mood', values: ['happy', 'sad', 'ok'] }] },
|
|
305
|
+
)
|
|
306
|
+
expect(out).toMatch(/Enums: {\s*mood: 'happy' \| 'sad' \| 'ok'/)
|
|
307
|
+
// La colonne enum référence le bloc Enums (auto-référence Supabase).
|
|
308
|
+
expect(out).toContain("mood: Database['public']['Enums']['mood']")
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
it("enum inconnu du bloc → repli string (compile-safe)", () => {
|
|
312
|
+
const out = generateDatabaseTypes([table('t', [col('x', { enum: 'unlisted' })])])
|
|
313
|
+
expect(out).toContain('x: string')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('array d’enum : {array:{enum:mood}} → Enums[mood][]', () => {
|
|
317
|
+
const out = generateDatabaseTypes(
|
|
318
|
+
[table('t', [col('moods', { array: { enum: 'mood' } })])],
|
|
319
|
+
{ enums: [{ name: 'mood', values: ['a', 'b'] }] },
|
|
320
|
+
)
|
|
321
|
+
expect(out).toContain("moods: Database['public']['Enums']['mood'][]")
|
|
322
|
+
})
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
describe('generateDatabaseTypes — Views (C6)', () => {
|
|
326
|
+
it('émet Views:{v:{Row}} (Row seul, Relationships:[])', () => {
|
|
327
|
+
const out = generateDatabaseTypes([], {
|
|
328
|
+
views: [table('v_active_users', [col('id', 'uuid'), col('email', 'text', { nullable: true })])],
|
|
329
|
+
})
|
|
330
|
+
const block = out.slice(out.indexOf('Views: '))
|
|
331
|
+
expect(block).toContain('v_active_users: {')
|
|
332
|
+
expect(block).toContain('Row: {')
|
|
333
|
+
expect(block).toContain('id: string')
|
|
334
|
+
expect(block).toContain('email: string | null')
|
|
335
|
+
expect(block).toContain('Relationships: []')
|
|
336
|
+
// Pas d'Insert/Update pour une vue.
|
|
337
|
+
const viewBlock = out.slice(out.indexOf('v_active_users: {'), out.indexOf('Functions:'))
|
|
338
|
+
expect(viewBlock).not.toContain('Insert:')
|
|
339
|
+
expect(viewBlock).not.toContain('Update:')
|
|
340
|
+
})
|
|
341
|
+
})
|
|
342
|
+
|
|
343
|
+
describe('generateDatabaseTypes — Functions : mapping udt_name bruts (C4)', () => {
|
|
344
|
+
it('array udt (_text) → string[], _int4 → number[] (PAS unknown)', () => {
|
|
345
|
+
const out = generateDatabaseTypes([], {
|
|
346
|
+
functions: [fn('tags_of', [{ name: 'ids', data_type: '_int4', mode: 'IN' }], '_text')],
|
|
347
|
+
})
|
|
348
|
+
const block = out.slice(out.indexOf('tags_of: {'), out.indexOf('tags_of: {') + 300)
|
|
349
|
+
expect(block).toContain('ids: number[]')
|
|
350
|
+
expect(block).toContain('Returns: string[]')
|
|
351
|
+
expect(block).not.toContain('unknown')
|
|
352
|
+
})
|
|
353
|
+
|
|
354
|
+
it('numeric → string (H5), timestamptz → string, bool → boolean', () => {
|
|
355
|
+
const out = generateDatabaseTypes([], {
|
|
356
|
+
functions: [fn('calc', [
|
|
357
|
+
{ name: 'amount', data_type: 'numeric', mode: 'IN' },
|
|
358
|
+
{ name: 'flag', data_type: 'bool', mode: 'IN' },
|
|
359
|
+
{ name: 'ts', data_type: 'timestamptz', mode: 'IN' },
|
|
360
|
+
], 'numeric')],
|
|
361
|
+
})
|
|
362
|
+
const block = out.slice(out.indexOf('calc: {'), out.indexOf('calc: {') + 300)
|
|
363
|
+
expect(block).toContain('amount: string')
|
|
364
|
+
expect(block).toContain('flag: boolean')
|
|
365
|
+
expect(block).toContain('ts: string')
|
|
366
|
+
expect(block).toContain('Returns: string')
|
|
367
|
+
})
|
|
368
|
+
|
|
369
|
+
it('argument/retour de type enum → référence le bloc Enums', () => {
|
|
370
|
+
const out = generateDatabaseTypes([], {
|
|
371
|
+
functions: [fn('set_mood', [{ name: 'm', data_type: 'mood', mode: 'IN' }], 'mood')],
|
|
372
|
+
enums: [{ name: 'mood', values: ['a', 'b'] }],
|
|
373
|
+
})
|
|
374
|
+
const block = out.slice(out.indexOf('set_mood: {'), out.indexOf('set_mood: {') + 300)
|
|
375
|
+
expect(block).toContain("m: Database['public']['Enums']['mood']")
|
|
376
|
+
expect(block).toContain("Returns: Database['public']['Enums']['mood']")
|
|
377
|
+
})
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
describe('generateDatabaseTypes — assemblage complet', () => {
|
|
381
|
+
it('émet Json, les blocs vides, l’en-tête, et respecte les options', () => {
|
|
382
|
+
const out = generateDatabaseTypes([table('users', [col('id', 'uuid')])], { typeName: 'DB', schemaName: 'public' })
|
|
383
|
+
expect(out).toContain('export type Json =')
|
|
384
|
+
expect(out).toContain('export interface DB {')
|
|
385
|
+
expect(out).toContain('Views: Record<string, never>')
|
|
386
|
+
expect(out).toContain('Functions: Record<string, never>')
|
|
387
|
+
expect(out).toContain('Enums: Record<string, never>')
|
|
388
|
+
expect(out).toContain('CompositeTypes: Record<string, never>')
|
|
389
|
+
expect(out).toContain('auto-généré')
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
it('schéma vide → Tables: Record<string, never>', () => {
|
|
393
|
+
const out = generateDatabaseTypes([])
|
|
394
|
+
expect(out).toContain('Tables: Record<string, never>')
|
|
395
|
+
})
|
|
396
|
+
})
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aurabase
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @aurabase/notifications
|
|
2
|
+
|
|
3
|
+
Service de notifications multi-canal du SDK Aurabase : email, SMS, push et webhook derrière une API unique, avec templates, règles déclenchées par événement et administration complète (`aura.notifications.admin`).
|
|
4
|
+
|
|
5
|
+
 
|
|
6
|
+
|
|
7
|
+
> Pre-release — pas encore publié sur npm.
|
|
8
|
+
|
|
9
|
+
Fait partie du SDK **[aurabase](../aurabase)**. Installé automatiquement avec `aurabase` ; ce package est publié séparément pour un usage ciblé / tree-shaking.
|
|
10
|
+
|
|
11
|
+
Le multi-canal unifié (un seul `send()` pour email/SMS/push/webhook, avec dead-letter, retries et règles) est un **différenciateur** face à des solutions push-only (FCM) ou tiers payantes (OneSignal).
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i @aurabase/notifications
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> Ce package dépend de `@aurabase/core` (`workspace:*` en interne, résolu en semver côté npm). Si vous utilisez déjà le package `aurabase`, `@aurabase/notifications` est déjà inclus — cette installation ciblée n'est utile que pour composer votre propre client ou limiter la taille du bundle.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
Dans l'usage courant, `NotificationsService` n'est jamais instancié directement : il est exposé par le client principal sous `aura.notifications` (et son admin sous `aura.notifications.admin`).
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { createClient } from 'aurabase'
|
|
27
|
+
|
|
28
|
+
const aura = createClient('http://localhost:8080', 'my-project', 'aura_anon_xxx')
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Envoi
|
|
32
|
+
|
|
33
|
+
Canaux disponibles : `'email' | 'sms' | 'push' | 'webhook'`.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const { data, error } = await aura.notifications.send(
|
|
37
|
+
'email',
|
|
38
|
+
'user@example.com',
|
|
39
|
+
'Votre commande a été expédiée.',
|
|
40
|
+
{ subject: 'Expédition', variables: { order_id: '1234' }, idempotencyKey: 'order-1234-shipped' },
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if (error) throw error
|
|
44
|
+
console.log(data!.status)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Envoi en lot
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const { data: batch } = await aura.notifications.sendBatch([
|
|
51
|
+
{ channel: 'email', recipient: 'a@example.com', body: 'Bonjour A' },
|
|
52
|
+
{ channel: 'sms', recipient: '+15551234567', body: 'Bonjour B' },
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
for (const item of batch!.items) {
|
|
56
|
+
console.log(item.status, item.notification?.id)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Historique et templates
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const { data: sent } = await aura.notifications.list({
|
|
64
|
+
channel: 'email',
|
|
65
|
+
status: 'delivered',
|
|
66
|
+
sort: 'created_at',
|
|
67
|
+
order: 'desc',
|
|
68
|
+
limit: 20,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const notificationId = sent![0]!.id
|
|
72
|
+
const { data: notif } = await aura.notifications.get(notificationId)
|
|
73
|
+
|
|
74
|
+
const { data: template } = await aura.notifications.createTemplate({
|
|
75
|
+
name: 'order-shipped',
|
|
76
|
+
channel: 'email',
|
|
77
|
+
subject: 'Expédition {{order_id}}',
|
|
78
|
+
body: 'Votre commande {{order_id}} est en route.',
|
|
79
|
+
variables: ['order_id'],
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
await aura.notifications.updateTemplate(template!.id, { body: 'Mise à jour : {{order_id}} expédiée.' })
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Administration (`aura.notifications.admin`)
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const { data: settings } = await aura.notifications.admin.getSettings()
|
|
89
|
+
await aura.notifications.admin.updateSettings({ quotas: { daily_email: 10000 } })
|
|
90
|
+
|
|
91
|
+
const { data: stats } = await aura.notifications.admin.getStats({ window: '24h', channel: 'email' })
|
|
92
|
+
const { data: queue } = await aura.notifications.admin.getQueue()
|
|
93
|
+
|
|
94
|
+
const failedId = 'notification-id'
|
|
95
|
+
const { data: attempts } = await aura.notifications.admin.listAttempts(failedId)
|
|
96
|
+
|
|
97
|
+
const { data: deadLetters } = await aura.notifications.admin.listDeadLetters({ channel: 'email', limit: 50 })
|
|
98
|
+
await aura.notifications.admin.retryDeadLetter(deadLetters![0]!.id)
|
|
99
|
+
|
|
100
|
+
const { data: events } = await aura.notifications.admin.listEvents({ status: 'failed' })
|
|
101
|
+
const { data: logs } = await aura.notifications.admin.listProviderLogs({ channel: 'sms' })
|
|
102
|
+
|
|
103
|
+
const templateId = 'template-id'
|
|
104
|
+
const { data: preview } = await aura.notifications.admin.previewTemplate(templateId, { order_id: '1234' })
|
|
105
|
+
console.log(preview!.subject, preview!.body)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Règles déclenchées par événement
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
const { data: rule } = await aura.notifications.admin.createRule({
|
|
112
|
+
name: 'welcome-email',
|
|
113
|
+
trigger_type: 'user.created',
|
|
114
|
+
channel: 'email',
|
|
115
|
+
recipient_expr: 'user.email',
|
|
116
|
+
template_id: 'welcome-template-id',
|
|
117
|
+
delay_seconds: 0,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
const { data: rules } = await aura.notifications.admin.listRules()
|
|
121
|
+
await aura.notifications.admin.updateRule(rule!.id, { enabled: false })
|
|
122
|
+
await aura.notifications.admin.deleteRule(rule!.id)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Limitations
|
|
126
|
+
|
|
127
|
+
- Pas de gestion d'audience/segments/devices : `recipient` est une chaîne brute (email, numéro, endpoint webhook, device token) — pas d'abstraction "device" ou "utilisateur" côté SDK.
|
|
128
|
+
- Pas de scheduling explicite d'un envoi (« envoyer à telle date ») en dehors du `delay_seconds` des règles déclenchées.
|
|
129
|
+
- Payloads génériques : `body` est une chaîne libre associée à des `variables` (interpolation côté backend), pas un objet structuré par canal (pas de builder push spécifique avec badge/son/icône, par exemple).
|
|
130
|
+
- Pas d'API de désabonnement/préférences par canal exposée par le SDK.
|
|
131
|
+
|
|
132
|
+
## Documentation
|
|
133
|
+
|
|
134
|
+
Référence complète du SDK (tous les services, types partagés, SSR) : [README racine](../../README.md).
|