mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat(provider): add github copilot device flow provider (#364)
This commit is contained in:
@@ -68,7 +68,7 @@ CREATE TABLE IF NOT EXISTS providers (
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT providers_name_unique UNIQUE (name),
|
||||
CONSTRAINT providers_client_type_check CHECK (client_type IN ('openai-responses', 'openai-completions', 'anthropic-messages', 'google-generative-ai', 'openai-codex', 'edge-speech'))
|
||||
CONSTRAINT providers_client_type_check CHECK (client_type IN ('openai-responses', 'openai-completions', 'anthropic-messages', 'google-generative-ai', 'openai-codex', 'github-copilot', 'edge-speech'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS search_providers (
|
||||
@@ -644,3 +644,23 @@ CREATE TABLE IF NOT EXISTS provider_oauth_tokens (
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_provider_oauth_tokens_state ON provider_oauth_tokens(state) WHERE state != '';
|
||||
|
||||
-- user_provider_oauth_tokens: per-user OAuth2 tokens for providers with user-scoped auth (e.g. GitHub Copilot)
|
||||
CREATE TABLE IF NOT EXISTS user_provider_oauth_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
provider_id UUID NOT NULL REFERENCES providers(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
access_token TEXT NOT NULL DEFAULT '',
|
||||
refresh_token TEXT NOT NULL DEFAULT '',
|
||||
expires_at TIMESTAMPTZ,
|
||||
scope TEXT NOT NULL DEFAULT '',
|
||||
token_type TEXT NOT NULL DEFAULT '',
|
||||
state TEXT NOT NULL DEFAULT '',
|
||||
pkce_code_verifier TEXT NOT NULL DEFAULT '',
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT user_provider_oauth_tokens_provider_user_unique UNIQUE (provider_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_provider_oauth_tokens_state ON user_provider_oauth_tokens(state) WHERE state != '';
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- 0062_github_copilot_user_oauth (rollback)
|
||||
-- Remove user-scoped provider OAuth tokens and github-copilot client type.
|
||||
|
||||
DROP INDEX IF EXISTS idx_user_provider_oauth_tokens_state;
|
||||
DROP TABLE IF EXISTS user_provider_oauth_tokens;
|
||||
|
||||
DELETE FROM providers WHERE client_type = 'github-copilot';
|
||||
|
||||
ALTER TABLE IF EXISTS providers DROP CONSTRAINT IF EXISTS providers_client_type_check;
|
||||
|
||||
ALTER TABLE IF EXISTS providers
|
||||
ADD CONSTRAINT providers_client_type_check CHECK (
|
||||
client_type IN (
|
||||
'openai-responses',
|
||||
'openai-completions',
|
||||
'anthropic-messages',
|
||||
'google-generative-ai',
|
||||
'openai-codex',
|
||||
'edge-speech'
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,38 @@
|
||||
-- 0062_github_copilot_user_oauth
|
||||
-- Add github-copilot as a provider client type and store OAuth tokens per user.
|
||||
|
||||
ALTER TABLE IF EXISTS providers DROP CONSTRAINT IF EXISTS providers_client_type_check;
|
||||
|
||||
ALTER TABLE IF EXISTS providers
|
||||
ADD CONSTRAINT providers_client_type_check CHECK (
|
||||
client_type IN (
|
||||
'openai-responses',
|
||||
'openai-completions',
|
||||
'anthropic-messages',
|
||||
'google-generative-ai',
|
||||
'openai-codex',
|
||||
'github-copilot',
|
||||
'edge-speech'
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_provider_oauth_tokens (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
provider_id UUID NOT NULL REFERENCES providers(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
access_token TEXT NOT NULL DEFAULT '',
|
||||
refresh_token TEXT NOT NULL DEFAULT '',
|
||||
expires_at TIMESTAMPTZ,
|
||||
scope TEXT NOT NULL DEFAULT '',
|
||||
token_type TEXT NOT NULL DEFAULT '',
|
||||
state TEXT NOT NULL DEFAULT '',
|
||||
pkce_code_verifier TEXT NOT NULL DEFAULT '',
|
||||
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT user_provider_oauth_tokens_provider_user_unique UNIQUE (provider_id, user_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_provider_oauth_tokens_state
|
||||
ON user_provider_oauth_tokens(state)
|
||||
WHERE state != '';
|
||||
@@ -0,0 +1,66 @@
|
||||
-- name: UpsertUserProviderOAuthToken :one
|
||||
INSERT INTO user_provider_oauth_tokens (
|
||||
provider_id,
|
||||
user_id,
|
||||
access_token,
|
||||
refresh_token,
|
||||
expires_at,
|
||||
scope,
|
||||
token_type,
|
||||
state,
|
||||
pkce_code_verifier,
|
||||
metadata
|
||||
)
|
||||
VALUES (
|
||||
sqlc.arg(provider_id),
|
||||
sqlc.arg(user_id),
|
||||
sqlc.arg(access_token),
|
||||
sqlc.arg(refresh_token),
|
||||
sqlc.arg(expires_at),
|
||||
sqlc.arg(scope),
|
||||
sqlc.arg(token_type),
|
||||
sqlc.arg(state),
|
||||
sqlc.arg(pkce_code_verifier),
|
||||
sqlc.arg(metadata)
|
||||
)
|
||||
ON CONFLICT (provider_id, user_id) DO UPDATE SET
|
||||
access_token = EXCLUDED.access_token,
|
||||
refresh_token = EXCLUDED.refresh_token,
|
||||
expires_at = EXCLUDED.expires_at,
|
||||
scope = EXCLUDED.scope,
|
||||
token_type = EXCLUDED.token_type,
|
||||
state = EXCLUDED.state,
|
||||
pkce_code_verifier = EXCLUDED.pkce_code_verifier,
|
||||
metadata = EXCLUDED.metadata,
|
||||
updated_at = now()
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetUserProviderOAuthToken :one
|
||||
SELECT * FROM user_provider_oauth_tokens
|
||||
WHERE provider_id = sqlc.arg(provider_id)
|
||||
AND user_id = sqlc.arg(user_id);
|
||||
|
||||
-- name: GetUserProviderOAuthTokenByState :one
|
||||
SELECT * FROM user_provider_oauth_tokens
|
||||
WHERE state = sqlc.arg(state)
|
||||
AND state != '';
|
||||
|
||||
-- name: UpdateUserProviderOAuthState :exec
|
||||
INSERT INTO user_provider_oauth_tokens (provider_id, user_id, state, pkce_code_verifier, metadata)
|
||||
VALUES (
|
||||
sqlc.arg(provider_id),
|
||||
sqlc.arg(user_id),
|
||||
sqlc.arg(state),
|
||||
sqlc.arg(pkce_code_verifier),
|
||||
sqlc.arg(metadata)
|
||||
)
|
||||
ON CONFLICT (provider_id, user_id) DO UPDATE SET
|
||||
state = EXCLUDED.state,
|
||||
pkce_code_verifier = EXCLUDED.pkce_code_verifier,
|
||||
metadata = EXCLUDED.metadata,
|
||||
updated_at = now();
|
||||
|
||||
-- name: DeleteUserProviderOAuthToken :exec
|
||||
DELETE FROM user_provider_oauth_tokens
|
||||
WHERE provider_id = sqlc.arg(provider_id)
|
||||
AND user_id = sqlc.arg(user_id);
|
||||
Reference in New Issue
Block a user