divi 0.0.1.dev11__tar.gz → 0.0.1.dev12__tar.gz
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.
- divi-0.0.1.dev12/.air.toml +61 -0
- divi-0.0.1.dev12/.dockerignore +1 -0
- divi-0.0.1.dev12/.github/dependabot.yml +11 -0
- divi-0.0.1.dev12/.gitignore +51 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/PKG-INFO +3 -1
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/README.md +7 -0
- divi-0.0.1.dev12/apps/README.md +15 -0
- divi-0.0.1.dev12/apps/graphql/Dockerfile +43 -0
- divi-0.0.1.dev12/apps/graphql/README.md +3 -0
- divi-0.0.1.dev12/apps/graphql/codegen.ts +19 -0
- divi-0.0.1.dev12/apps/graphql/package.json +29 -0
- divi-0.0.1.dev12/apps/graphql/src/datasources/auth-api.ts +65 -0
- divi-0.0.1.dev12/apps/graphql/src/index.ts +32 -0
- divi-0.0.1.dev12/apps/graphql/src/resolvers.ts +82 -0
- divi-0.0.1.dev12/apps/graphql/src/schema.graphql +91 -0
- divi-0.0.1.dev12/apps/graphql/src/types/api-key.d.ts +4 -0
- divi-0.0.1.dev12/apps/graphql/src/types/context.d.ts +7 -0
- divi-0.0.1.dev12/apps/graphql/src/types/response.d.ts +16 -0
- divi-0.0.1.dev12/apps/graphql/src/types/types.d.ts +374 -0
- divi-0.0.1.dev12/apps/graphql/src/types/user.d.ts +9 -0
- divi-0.0.1.dev12/apps/graphql/tsconfig.json +13 -0
- divi-0.0.1.dev12/apps/web/.gitignore +36 -0
- divi-0.0.1.dev12/apps/web/README.md +36 -0
- divi-0.0.1.dev12/apps/web/app/favicon.ico +0 -0
- divi-0.0.1.dev12/apps/web/app/layout.tsx +27 -0
- divi-0.0.1.dev12/apps/web/app/login/page.tsx +43 -0
- divi-0.0.1.dev12/apps/web/app/page.tsx +10 -0
- divi-0.0.1.dev12/apps/web/app/signup/page.tsx +62 -0
- divi-0.0.1.dev12/apps/web/components/ApolloWrapper.tsx +40 -0
- divi-0.0.1.dev12/apps/web/components/login-form.tsx +71 -0
- divi-0.0.1.dev12/apps/web/components/signup-form.tsx +51 -0
- divi-0.0.1.dev12/apps/web/components.json +20 -0
- divi-0.0.1.dev12/apps/web/hooks/apolloClient.ts +19 -0
- divi-0.0.1.dev12/apps/web/next-env.d.ts +5 -0
- divi-0.0.1.dev12/apps/web/next.config.ts +5 -0
- divi-0.0.1.dev12/apps/web/package.json +32 -0
- divi-0.0.1.dev12/apps/web/postcss.config.mjs +1 -0
- divi-0.0.1.dev12/apps/web/public/peeking-angel.png +0 -0
- divi-0.0.1.dev12/apps/web/public/thinking-angel.png +0 -0
- divi-0.0.1.dev12/apps/web/tsconfig.json +17 -0
- divi-0.0.1.dev12/biome.json +30 -0
- divi-0.0.1.dev12/divi/__init__.py +16 -0
- divi-0.0.1.dev12/divi/decorators/__init__.py +4 -0
- divi-0.0.1.dev12/divi/decorators/obs_openai.py +33 -0
- divi-0.0.1.dev12/divi/decorators/observable.py +40 -0
- divi-0.0.1.dev12/divi/proto/common/v1/common.proto +63 -0
- divi-0.0.1.dev12/divi/proto/core/health/v1/health_service.proto +17 -0
- divi-0.0.1.dev12/divi/proto/resource/v1/resource.proto +19 -0
- divi-0.0.1.dev12/divi/proto/trace/v1/trace.proto +18 -0
- divi-0.0.1.dev12/divi/run/__init__.py +3 -0
- divi-0.0.1.dev12/divi/run/run.py +2 -0
- divi-0.0.1.dev12/divi/services/__init__.py +7 -0
- divi-0.0.1.dev12/divi/services/auth/__init__.py +4 -0
- divi-0.0.1.dev12/divi/services/auth/auth.py +21 -0
- divi-0.0.1.dev12/divi/services/auth/init.py +24 -0
- divi-0.0.1.dev12/divi/services/auth/tokman.py +42 -0
- divi-0.0.1.dev12/divi/services/core/__init__.py +5 -0
- divi-0.0.1.dev12/divi/services/core/core.py +35 -0
- {divi-0.0.1.dev11/divi → divi-0.0.1.dev12/divi/services}/core/finish.py +4 -4
- {divi-0.0.1.dev11/divi → divi-0.0.1.dev12/divi/services}/core/init.py +23 -22
- divi-0.0.1.dev12/divi/services/datapark/__init__.py +3 -0
- divi-0.0.1.dev12/divi/services/datapark/datapark.py +6 -0
- divi-0.0.1.dev12/divi/services/datapark/init.py +9 -0
- divi-0.0.1.dev12/divi/services/finish.py +5 -0
- divi-0.0.1.dev12/divi/services/init.py +7 -0
- divi-0.0.1.dev12/divi/services/service.py +11 -0
- divi-0.0.1.dev12/divi/signals/__init__.py +4 -0
- divi-0.0.1.dev12/divi/signals/metric/__init__.py +3 -0
- divi-0.0.1.dev12/divi/signals/metric/metric.py +2 -0
- divi-0.0.1.dev12/divi/signals/trace/__init__.py +3 -0
- divi-0.0.1.dev12/divi/signals/trace/trace.py +2 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/divi/utils.py +8 -0
- divi-0.0.1.dev12/docker-compose.yml +62 -0
- divi-0.0.1.dev12/go.work.sum +46 -0
- divi-0.0.1.dev12/package.json +23 -0
- divi-0.0.1.dev12/packages/README.md +15 -0
- divi-0.0.1.dev12/pnpm-lock.yaml +6927 -0
- divi-0.0.1.dev12/pnpm-workspace.yaml +4 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/pyproject.toml +13 -2
- divi-0.0.1.dev12/scripts/key_build.py +46 -0
- divi-0.0.1.dev12/services/README.md +15 -0
- divi-0.0.1.dev12/services/go.mod +45 -0
- divi-0.0.1.dev12/services/go.sum +109 -0
- divi-0.0.1.dev12/services/internal/app/auth/handler/api.go +8 -0
- divi-0.0.1.dev12/services/internal/app/auth/handler/api_key.go +78 -0
- divi-0.0.1.dev12/services/internal/app/auth/handler/auth.go +155 -0
- divi-0.0.1.dev12/services/internal/app/auth/handler/user.go +162 -0
- divi-0.0.1.dev12/services/internal/app/auth/middleware/auth.go +30 -0
- divi-0.0.1.dev12/services/internal/app/auth/router/router.go +37 -0
- divi-0.0.1.dev12/services/internal/pkg/auth/auth.go +32 -0
- divi-0.0.1.dev12/services/internal/pkg/config/config.go +22 -0
- divi-0.0.1.dev12/services/internal/pkg/database/connect.go +39 -0
- divi-0.0.1.dev12/services/internal/pkg/database/database.go +6 -0
- divi-0.0.1.dev12/services/internal/pkg/model/api_key.go +16 -0
- divi-0.0.1.dev12/services/internal/pkg/model/user.go +22 -0
- divi-0.0.1.dev12/tests/__init__.py +1 -0
- divi-0.0.1.dev12/tests/unit_tests/decorators/test_obs_openai.py +54 -0
- divi-0.0.1.dev12/tests/unit_tests/decorators/test_observable.py +18 -0
- divi-0.0.1.dev12/turbo.json +35 -0
- divi-0.0.1.dev12/uv.lock +637 -0
- divi-0.0.1.dev11/.gitignore +0 -16
- divi-0.0.1.dev11/apps/README.md +0 -3
- divi-0.0.1.dev11/divi/__init__.py +0 -9
- divi-0.0.1.dev11/divi/core/__init__.py +0 -5
- divi-0.0.1.dev11/divi/core/run.py +0 -34
- divi-0.0.1.dev11/divi/proto/core.proto +0 -12
- divi-0.0.1.dev11/divi/proto/core_pb2.py +0 -38
- divi-0.0.1.dev11/divi/proto/core_pb2.pyi +0 -5
- divi-0.0.1.dev11/divi/proto/core_pb2_grpc.py +0 -100
- divi-0.0.1.dev11/divi/proto/health.proto +0 -12
- divi-0.0.1.dev11/divi/proto/health_pb2.py +0 -39
- divi-0.0.1.dev11/divi/proto/health_pb2.pyi +0 -19
- divi-0.0.1.dev11/go.work.sum +0 -19
- divi-0.0.1.dev11/services/README.md +0 -7
- divi-0.0.1.dev11/services/cmd/auth/auth.go +0 -1
- divi-0.0.1.dev11/services/cmd/core/core.go +0 -44
- divi-0.0.1.dev11/services/cmd/datapark/datapark.go +0 -1
- divi-0.0.1.dev11/services/go.mod +0 -15
- divi-0.0.1.dev11/services/go.sum +0 -32
- divi-0.0.1.dev11/services/internal/pkg/.keep +0 -0
- divi-0.0.1.dev11/uv.lock +0 -178
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/LICENSE +0 -0
- /divi-0.0.1.dev11/services/internal/app/auth/.keep → /divi-0.0.1.dev12/divi/config/config.py +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/docs/README.md +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/docs/package_readme.md +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/go.work +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/hatch.toml +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/scripts/README.md +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/scripts/hatch_build.py +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/scripts/proto_build.py +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/services/internal/app/core/.keep +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/services/internal/app/datapark/.keep +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/services/proto/core.pb.go +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/services/proto/core_grpc.pb.go +0 -0
- {divi-0.0.1.dev11 → divi-0.0.1.dev12}/services/proto/health.pb.go +0 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format
|
2
|
+
|
3
|
+
# Working directory
|
4
|
+
# . or absolute path, please note that the directories following must be under root.
|
5
|
+
root = "."
|
6
|
+
tmp_dir = "tmp"
|
7
|
+
|
8
|
+
[build]
|
9
|
+
# Just plain old shell command. You could use `make` as well.
|
10
|
+
cmd = "go build -o ./tmp/auth ./services/cmd/auth/auth.go"
|
11
|
+
# Binary file yields from `cmd`.
|
12
|
+
bin = "tmp/auth"
|
13
|
+
# Customize binary, can setup environment variables when run your app.
|
14
|
+
full_bin = "APP_ENV=dev APP_USER=air ./tmp/auth"
|
15
|
+
# Watch these filename extensions.
|
16
|
+
include_ext = ["go"]
|
17
|
+
# Watch these directories if you specified.
|
18
|
+
include_dir = ["services"]
|
19
|
+
# Exclude specific regular expressions.
|
20
|
+
exclude_regex = ["_test\\.go"]
|
21
|
+
# Exclude unchanged files.
|
22
|
+
exclude_unchanged = true
|
23
|
+
# Follow symlink for directories
|
24
|
+
follow_symlink = true
|
25
|
+
# This log file places in your tmp_dir.
|
26
|
+
log = "air.log"
|
27
|
+
# Poll files for changes instead of using fsnotify.
|
28
|
+
poll = false
|
29
|
+
# Poll interval (defaults to the minimum interval of 500ms).
|
30
|
+
poll_interval = 500 # ms
|
31
|
+
# It's not necessary to trigger build each time file changes if it's too frequent.
|
32
|
+
delay = 0 # ms
|
33
|
+
# Stop running old binary when build errors occur.
|
34
|
+
stop_on_error = true
|
35
|
+
# Send Interrupt signal before killing process (windows does not support this feature)
|
36
|
+
send_interrupt = false
|
37
|
+
# Delay after sending Interrupt signal
|
38
|
+
kill_delay = 500 # ms
|
39
|
+
# Rerun binary or not
|
40
|
+
rerun = false
|
41
|
+
# Delay after each executions
|
42
|
+
rerun_delay = 500
|
43
|
+
# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'.
|
44
|
+
args_bin = []
|
45
|
+
|
46
|
+
[log]
|
47
|
+
# Show log time
|
48
|
+
time = false
|
49
|
+
# Only show main log (silences watcher, build, runner)
|
50
|
+
main_only = false
|
51
|
+
|
52
|
+
[color]
|
53
|
+
# Customize each part's color. If no color found, use the raw app log.
|
54
|
+
main = "magenta"
|
55
|
+
watcher = "cyan"
|
56
|
+
build = "yellow"
|
57
|
+
runner = "green"
|
58
|
+
|
59
|
+
[misc]
|
60
|
+
# Delete tmp directory on exit
|
61
|
+
clean_on_exit = true
|
@@ -0,0 +1 @@
|
|
1
|
+
node_modules
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
3
|
+
# Please see the documentation for all configuration options:
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
5
|
+
|
6
|
+
version: 2
|
7
|
+
updates:
|
8
|
+
- package-ecosystem: "" # See documentation for possible values
|
9
|
+
directory: "/" # Location of package manifests
|
10
|
+
schedule:
|
11
|
+
interval: "weekly"
|
@@ -0,0 +1,51 @@
|
|
1
|
+
.vscode/
|
2
|
+
.idea/
|
3
|
+
|
4
|
+
# Byte-compiled / optimized / DLL files
|
5
|
+
__pycache__/
|
6
|
+
*.py[cod]
|
7
|
+
*$py.class
|
8
|
+
|
9
|
+
# Distribution / packaging
|
10
|
+
.next/
|
11
|
+
dist/
|
12
|
+
out/
|
13
|
+
tmp/
|
14
|
+
build/
|
15
|
+
bin/
|
16
|
+
|
17
|
+
# Environments
|
18
|
+
.venv/
|
19
|
+
.env
|
20
|
+
|
21
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
22
|
+
|
23
|
+
# Dependencies
|
24
|
+
node_modules
|
25
|
+
.pnp
|
26
|
+
.pnp.js
|
27
|
+
|
28
|
+
# Local env files
|
29
|
+
.env
|
30
|
+
.env.local
|
31
|
+
.env.development.local
|
32
|
+
.env.test.local
|
33
|
+
.env.production.local
|
34
|
+
|
35
|
+
# Testing
|
36
|
+
coverage
|
37
|
+
|
38
|
+
# Turbo
|
39
|
+
.turbo
|
40
|
+
|
41
|
+
# Vercel
|
42
|
+
.vercel
|
43
|
+
|
44
|
+
# Debug
|
45
|
+
npm-debug.log*
|
46
|
+
yarn-debug.log*
|
47
|
+
yarn-error.log*
|
48
|
+
|
49
|
+
# Misc
|
50
|
+
.DS_Store
|
51
|
+
*.pem
|
@@ -1,11 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: divi
|
3
|
-
Version: 0.0.1.
|
3
|
+
Version: 0.0.1.dev12
|
4
4
|
Summary: The Agent Platform for Observability & Evaluation
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.11
|
7
7
|
Requires-Dist: grpcio>=1.69.0
|
8
8
|
Requires-Dist: protobuf>=5.29.3
|
9
|
+
Requires-Dist: pyjwt>=2.10.1
|
10
|
+
Requires-Dist: requests>=2.32.3
|
9
11
|
Description-Content-Type: text/markdown
|
10
12
|
|
11
13
|
# Divine Agent
|
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
Agent Platform for Observability • Evaluation • Playground
|
4
4
|
|
5
|
+
## TODO
|
6
|
+
|
7
|
+
- [ ] trace: obs_openai()
|
8
|
+
- [ ] trace: @obs
|
9
|
+
- [ ] datapark services
|
10
|
+
|
5
11
|
## Structure
|
6
12
|
|
7
13
|
> Divine Agent is a monorepo project. The project is structured as follows:
|
@@ -21,3 +27,4 @@ Agent Platform for Observability • Evaluation • Playground
|
|
21
27
|
1. [uv](https://github.com/astral-sh/uv): An extremely fast Python package and project manager, written in Rust.
|
22
28
|
2. [hatch](https://github.com/pypa/hatch): Hatch is a modern, extensible Python project manager.
|
23
29
|
3. [github cli](https://cli.github.com/manual): GitHub CLI, or gh, is a command-line interface to GitHub for use in your terminal or your scripts.
|
30
|
+
4. [turborepo](https://github.com/vercel/turborepo): Build system optimized for JavaScript and TypeScript, written in Rust
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Apps
|
2
|
+
|
3
|
+
> A series of web applications.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
| Name | Description | Port |
|
8
|
+
| --- | --- | --- |
|
9
|
+
| graphql | A GraphQL server | 4000 |
|
10
|
+
| web | A Next.js web server | 4001 |
|
11
|
+
| docs | A documentation server | 4002 |
|
12
|
+
|
13
|
+
## Rules
|
14
|
+
|
15
|
+
1. [Split project files by feature or route](https://nextjs.org/docs/app/getting-started/project-structure#split-project-files-by-feature-or-route)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
FROM node:23-alpine AS base
|
2
|
+
|
3
|
+
FROM base AS builder
|
4
|
+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
5
|
+
RUN apk update
|
6
|
+
RUN apk add --no-cache libc6-compat
|
7
|
+
# 启用 corepack 并激活 pnpm
|
8
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
9
|
+
# Set working directory
|
10
|
+
WORKDIR /app
|
11
|
+
# 使用 yarn 全局安装 turbo
|
12
|
+
RUN yarn global add turbo
|
13
|
+
COPY . .
|
14
|
+
RUN turbo prune @app/graphql --docker
|
15
|
+
|
16
|
+
# Add lockfile and package.json's of isolated subworkspace
|
17
|
+
FROM base AS installer
|
18
|
+
RUN apk update
|
19
|
+
RUN apk add --no-cache libc6-compat
|
20
|
+
# 启用 corepack 并激活 pnpm
|
21
|
+
RUN corepack enable && corepack prepare pnpm@latest --activate
|
22
|
+
WORKDIR /app
|
23
|
+
|
24
|
+
# First install dependencies (as they change less often)
|
25
|
+
COPY --from=builder /app/out/json/ .
|
26
|
+
COPY --from=builder /app/out/pnpm-lock.yaml .
|
27
|
+
RUN pnpm install
|
28
|
+
|
29
|
+
# Build the project and its dependencies
|
30
|
+
COPY --from=builder /app/out/full/ .
|
31
|
+
RUN pnpm turbo build
|
32
|
+
|
33
|
+
FROM base AS runner
|
34
|
+
WORKDIR /app
|
35
|
+
|
36
|
+
# Don't run production as root
|
37
|
+
RUN addgroup --system --gid 1001 divi
|
38
|
+
RUN adduser --system --uid 1001 divi
|
39
|
+
USER divi
|
40
|
+
COPY --from=installer /app .
|
41
|
+
|
42
|
+
EXPOSE 4000
|
43
|
+
CMD ["node", "apps/graphql/dist/index.js"]
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import type { CodegenConfig } from '@graphql-codegen/cli';
|
2
|
+
|
3
|
+
const config: CodegenConfig = {
|
4
|
+
schema: './src/schema.graphql',
|
5
|
+
generates: {
|
6
|
+
'./src/types/types.d.ts': {
|
7
|
+
plugins: ['typescript', 'typescript-resolvers'],
|
8
|
+
config: {
|
9
|
+
contextType: './context#DataSourceContext',
|
10
|
+
mappers: {
|
11
|
+
User: './user#UserModel',
|
12
|
+
APIKey: './api-key#APIKeyModel',
|
13
|
+
},
|
14
|
+
},
|
15
|
+
},
|
16
|
+
},
|
17
|
+
};
|
18
|
+
|
19
|
+
export default config;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"name": "@app/graphql",
|
3
|
+
"private": true,
|
4
|
+
"version": "0.1.0",
|
5
|
+
"main": "index.ts",
|
6
|
+
"scripts": {
|
7
|
+
"dev": "ts-node-dev --respawn ./src/index.ts",
|
8
|
+
"build": "tsc",
|
9
|
+
"start": "npm run build && nodemon ./dist/index.js",
|
10
|
+
"prebuild": "graphql-codegen",
|
11
|
+
"postbuild": "cp src/schema.graphql dist/"
|
12
|
+
},
|
13
|
+
"dependencies": {
|
14
|
+
"@apollo/datasource-rest": "^6.4.1",
|
15
|
+
"@apollo/server": "^4.11.3",
|
16
|
+
"@apollo/utils.keyvaluecache": "^3.1.0",
|
17
|
+
"graphql": "^16.10.0",
|
18
|
+
"graphql-tag": "^2.12.6"
|
19
|
+
},
|
20
|
+
"devDependencies": {
|
21
|
+
"@graphql-codegen/cli": "^4.0.1",
|
22
|
+
"@graphql-codegen/typescript": "^4.1.5",
|
23
|
+
"@graphql-codegen/typescript-resolvers": "^4.4.4",
|
24
|
+
"@workspace/typescript-config": "workspace:*",
|
25
|
+
"nodemon": "^3.1.9",
|
26
|
+
"ts-node-dev": "^2.0.0",
|
27
|
+
"typescript": "^5.7.3"
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
import type { APIKeyModel } from '@/types/api-key';
|
2
|
+
import type { FetchResponse } from '@/types/response';
|
3
|
+
import type { UserModel } from '@/types/user';
|
4
|
+
import { type AugmentedRequest, RESTDataSource } from '@apollo/datasource-rest';
|
5
|
+
import type { KeyValueCache } from '@apollo/utils.keyvaluecache';
|
6
|
+
|
7
|
+
export class AuthAPI extends RESTDataSource {
|
8
|
+
override baseURL = process.env.AUTH_SERVICE_URL ?? 'http://localhost:3000/';
|
9
|
+
private token: string;
|
10
|
+
|
11
|
+
constructor(options: { token: string; cache: KeyValueCache }) {
|
12
|
+
super(options);
|
13
|
+
this.token = options.token;
|
14
|
+
}
|
15
|
+
|
16
|
+
override willSendRequest(_path: string, request: AugmentedRequest) {
|
17
|
+
request.headers.authorization = this.token;
|
18
|
+
}
|
19
|
+
|
20
|
+
async createUser(email: string, password: string, username: string) {
|
21
|
+
return await this.post<FetchResponse<UserModel>>('/api/user/', {
|
22
|
+
body: { email, password, username },
|
23
|
+
});
|
24
|
+
}
|
25
|
+
|
26
|
+
async getUser(userId: string) {
|
27
|
+
return await this.get<FetchResponse<UserModel>>(`/api/user/${userId}`);
|
28
|
+
}
|
29
|
+
|
30
|
+
async updateUser(userId: string, name: string) {
|
31
|
+
return await this.patch<FetchResponse<UserModel>>(`/api/user/${userId}`, {
|
32
|
+
body: { name },
|
33
|
+
});
|
34
|
+
}
|
35
|
+
|
36
|
+
async deleteUser(userId: string, password: string) {
|
37
|
+
return await this.delete<FetchResponse<null>>(`/api/user/${userId}`, {
|
38
|
+
body: { password },
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
42
|
+
async getAPIKeys() {
|
43
|
+
return await this.get<FetchResponse<APIKeyModel[]>>('/api/api_key/');
|
44
|
+
}
|
45
|
+
|
46
|
+
async createAPIKey() {
|
47
|
+
return await this.post<FetchResponse<APIKeyModel>>('/api/api_key/');
|
48
|
+
}
|
49
|
+
|
50
|
+
async revokeAPIKey(apiKeyId: string) {
|
51
|
+
return await this.delete<FetchResponse<null>>(`/api/api_key/${apiKeyId}`);
|
52
|
+
}
|
53
|
+
|
54
|
+
async login(identity: string, password: string) {
|
55
|
+
return await this.post<FetchResponse<string>>('/api/auth/login', {
|
56
|
+
body: { identity, password },
|
57
|
+
});
|
58
|
+
}
|
59
|
+
|
60
|
+
async loginWithAPIKey(apiKey: string) {
|
61
|
+
return await this.post<FetchResponse<string>>('/api/auth/api_key', {
|
62
|
+
body: { api_key: apiKey },
|
63
|
+
});
|
64
|
+
}
|
65
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
2
|
+
import { join } from 'node:path';
|
3
|
+
import { ApolloServer } from '@apollo/server';
|
4
|
+
import { startStandaloneServer } from '@apollo/server/standalone';
|
5
|
+
import gql from 'graphql-tag';
|
6
|
+
import { AuthAPI } from './datasources/auth-api';
|
7
|
+
import { resolvers } from './resolvers';
|
8
|
+
|
9
|
+
const typeDefs = gql(
|
10
|
+
readFileSync(join(__dirname, './schema.graphql'), { encoding: 'utf-8' })
|
11
|
+
);
|
12
|
+
|
13
|
+
async function startApolloServer() {
|
14
|
+
const server = new ApolloServer({ typeDefs, resolvers });
|
15
|
+
const { url } = await startStandaloneServer(server, {
|
16
|
+
context: ({ req }) => {
|
17
|
+
const token = req.headers.authorization || '';
|
18
|
+
const { cache } = server;
|
19
|
+
return Promise.resolve({
|
20
|
+
dataSources: {
|
21
|
+
authAPI: new AuthAPI({ token, cache }),
|
22
|
+
},
|
23
|
+
});
|
24
|
+
},
|
25
|
+
});
|
26
|
+
console.info(`
|
27
|
+
🚀 Server is running!
|
28
|
+
📭 Query at ${url}
|
29
|
+
`);
|
30
|
+
}
|
31
|
+
|
32
|
+
startApolloServer();
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import type {
|
2
|
+
ErrorResponse,
|
3
|
+
FetchResponse,
|
4
|
+
MutationResponse,
|
5
|
+
} from '@/types/response';
|
6
|
+
import type { Resolvers } from '@/types/types';
|
7
|
+
import type { GraphQLError } from 'graphql';
|
8
|
+
|
9
|
+
export const resolvers: Resolvers = {
|
10
|
+
Query: {
|
11
|
+
user: async (_, { id }, { dataSources }) => {
|
12
|
+
return (await dataSources.authAPI.getUser(id)).data;
|
13
|
+
},
|
14
|
+
},
|
15
|
+
Mutation: {
|
16
|
+
createAPIKey: async (_, _args, { dataSources }) => {
|
17
|
+
return await mutationAdaptor(dataSources.authAPI.createAPIKey());
|
18
|
+
},
|
19
|
+
revokeAPIKey: async (_, { id }, { dataSources }) => {
|
20
|
+
return await mutationAdaptor(dataSources.authAPI.revokeAPIKey(id));
|
21
|
+
},
|
22
|
+
login: async (_, { identity, password }, { dataSources }) => {
|
23
|
+
return await mutationAdaptor(
|
24
|
+
dataSources.authAPI.login(identity, password)
|
25
|
+
);
|
26
|
+
},
|
27
|
+
loginWithAPIKey: async (_, { api_key }, { dataSources }) => {
|
28
|
+
return await mutationAdaptor(
|
29
|
+
dataSources.authAPI.loginWithAPIKey(api_key)
|
30
|
+
);
|
31
|
+
},
|
32
|
+
deleteUser: async (_, { id, password }, { dataSources }) => {
|
33
|
+
return await mutationAdaptor(
|
34
|
+
dataSources.authAPI.deleteUser(id, password)
|
35
|
+
);
|
36
|
+
},
|
37
|
+
updateUser: async (_, { id, name }, { dataSources }) => {
|
38
|
+
return await mutationAdaptor(dataSources.authAPI.updateUser(id, name));
|
39
|
+
},
|
40
|
+
createUser: async (_, { email, password, username }, { dataSources }) => {
|
41
|
+
return await mutationAdaptor(
|
42
|
+
dataSources.authAPI.createUser(email, password, username)
|
43
|
+
);
|
44
|
+
},
|
45
|
+
},
|
46
|
+
User: {
|
47
|
+
api_keys: async (_user, _args, { dataSources }) => {
|
48
|
+
return (await dataSources.authAPI.getAPIKeys()).data;
|
49
|
+
},
|
50
|
+
},
|
51
|
+
};
|
52
|
+
|
53
|
+
/**
|
54
|
+
* mutationAdaptor is a utility function that adapts a FetchResponse to a MutationResponse
|
55
|
+
* @param { Promise<FetchResponse<T>> } f
|
56
|
+
* @returns { MutationResponse<T> }
|
57
|
+
*/
|
58
|
+
async function mutationAdaptor<T>(
|
59
|
+
f: Promise<FetchResponse<T>>
|
60
|
+
): Promise<MutationResponse<T | null>> {
|
61
|
+
return f
|
62
|
+
.then((response): MutationResponse<T> => {
|
63
|
+
return {
|
64
|
+
...response,
|
65
|
+
code: 200,
|
66
|
+
success: true,
|
67
|
+
};
|
68
|
+
})
|
69
|
+
.catch((error: GraphQLError): MutationResponse<null> => {
|
70
|
+
const response = error.extensions.response as ErrorResponse;
|
71
|
+
// message = response.body if response.body is string else response.body.message
|
72
|
+
if (typeof response.body === 'string') {
|
73
|
+
response.body = { message: response.body, data: null };
|
74
|
+
}
|
75
|
+
return {
|
76
|
+
code: response.status,
|
77
|
+
success: false,
|
78
|
+
message: response.body.message,
|
79
|
+
data: null,
|
80
|
+
};
|
81
|
+
});
|
82
|
+
}
|
@@ -0,0 +1,91 @@
|
|
1
|
+
"Query is a collection of queries that can be made to the API"
|
2
|
+
type Query {
|
3
|
+
"Fetch a specific user by id"
|
4
|
+
user(id: ID!): User!
|
5
|
+
}
|
6
|
+
|
7
|
+
"User is a registered user of the application"
|
8
|
+
type User {
|
9
|
+
id: ID!
|
10
|
+
name: String
|
11
|
+
username: String!
|
12
|
+
email: String!
|
13
|
+
api_keys: [APIKey]
|
14
|
+
}
|
15
|
+
|
16
|
+
"APIKey is a key used to authenticate requests to the API"
|
17
|
+
type APIKey {
|
18
|
+
id: ID!
|
19
|
+
api_key: String!
|
20
|
+
}
|
21
|
+
|
22
|
+
"Mutation is a collection of mutations that can be made to the API"
|
23
|
+
type Mutation {
|
24
|
+
"Auth Mutations"
|
25
|
+
login(identity: String!, password: String!): CreateTokenResponse!
|
26
|
+
loginWithAPIKey(api_key: String!): CreateTokenResponse!
|
27
|
+
"API Key Mutations"
|
28
|
+
createAPIKey: CreateAPIKeyResponse!
|
29
|
+
revokeAPIKey(id: ID!): RevokeAPIKeyResponse!
|
30
|
+
"User Mutations"
|
31
|
+
createUser(
|
32
|
+
username: String!
|
33
|
+
email: String!
|
34
|
+
password: String!
|
35
|
+
): CreateUserResponse!
|
36
|
+
updateUser(id: ID!, name: String!): UpdateUserResponse!
|
37
|
+
deleteUser(id: ID!, password: String!): DeleteUserResponse!
|
38
|
+
}
|
39
|
+
|
40
|
+
"MutationResponse is a response to a mutation"
|
41
|
+
interface MutationResponse {
|
42
|
+
code: Int!
|
43
|
+
message: String!
|
44
|
+
success: Boolean!
|
45
|
+
}
|
46
|
+
|
47
|
+
"CreateAPIKeyResponse is a response to the createAPIKey mutation"
|
48
|
+
type CreateAPIKeyResponse implements MutationResponse {
|
49
|
+
code: Int!
|
50
|
+
message: String!
|
51
|
+
success: Boolean!
|
52
|
+
data: APIKey
|
53
|
+
}
|
54
|
+
|
55
|
+
"RevokeAPIKeyResponse is a response to the revokeAPIKey mutation"
|
56
|
+
type RevokeAPIKeyResponse implements MutationResponse {
|
57
|
+
code: Int!
|
58
|
+
message: String!
|
59
|
+
success: Boolean!
|
60
|
+
}
|
61
|
+
|
62
|
+
"CreateTokenResponse is a response to the login mutation"
|
63
|
+
type CreateTokenResponse implements MutationResponse {
|
64
|
+
code: Int!
|
65
|
+
message: String!
|
66
|
+
success: Boolean!
|
67
|
+
data: String
|
68
|
+
}
|
69
|
+
|
70
|
+
"DeleteUserResponse is a response to the deleteUser mutation"
|
71
|
+
type DeleteUserResponse implements MutationResponse {
|
72
|
+
code: Int!
|
73
|
+
message: String!
|
74
|
+
success: Boolean!
|
75
|
+
}
|
76
|
+
|
77
|
+
"UpdateUserResponse is a response to the updateUser mutation"
|
78
|
+
type UpdateUserResponse implements MutationResponse {
|
79
|
+
code: Int!
|
80
|
+
message: String!
|
81
|
+
success: Boolean!
|
82
|
+
data: User
|
83
|
+
}
|
84
|
+
|
85
|
+
"CreateUserResponse is a response to the createUser mutation"
|
86
|
+
type CreateUserResponse implements MutationResponse {
|
87
|
+
code: Int!
|
88
|
+
message: String!
|
89
|
+
success: Boolean!
|
90
|
+
data: User
|
91
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export type FetchResponse<T> = {
|
2
|
+
message: string;
|
3
|
+
data: T;
|
4
|
+
};
|
5
|
+
|
6
|
+
export type MutationResponse<T> = FetchResponse<T> & {
|
7
|
+
code: number;
|
8
|
+
success: boolean;
|
9
|
+
};
|
10
|
+
|
11
|
+
export type ErrorResponse = {
|
12
|
+
url: string;
|
13
|
+
status: number;
|
14
|
+
statusText: string;
|
15
|
+
body: FetchResponse<null>;
|
16
|
+
};
|