This commit is contained in:
seb
2026-10-12 22:32:21 +02:00
parent 28e62093b3
commit 8a8aeaedd7
21 changed files with 786 additions and 4 deletions

View File

@@ -0,0 +1,16 @@
import { CONSUME_AUTH_CODE as MSSQL_CONSUME } from '../../providers/mssql/queries/mcp.js';
import { CONSUME_AUTH_CODE as SQLITE_CONSUME } from '../../providers/sqlite3/queries/mcp.js';
export default function consumeAuthCode(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_CONSUME : MSSQL_CONSUME;
/**
* Marks an authorization code as used.
*
* @param {string} code - The authorization code to mark used.
* @returns {Promise<boolean>} True once marked.
*/
return async (code) => {
await provider.query(sql, { code });
return true;
};
}

View File

@@ -0,0 +1,43 @@
import { INSERT_AUTH_CODE as MSSQL_INSERT } from '../../providers/mssql/queries/mcp.js';
import { INSERT_AUTH_CODE as SQLITE_INSERT } from '../../providers/sqlite3/queries/mcp.js';
export default function createAuthCode(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_INSERT : MSSQL_INSERT;
/**
* Stores an OAuth 2.1 authorization code with PKCE parameters.
*
* @param {object} input
* @param {string} input.code - The generated authorization code.
* @param {string} input.clientId - The client ID.
* @param {number} input.googleAuthId - The ID of the authenticated user.
* @param {string} input.redirectUri - The redirect URI used in the authorize request.
* @param {string} input.codeChallenge - The PKCE code challenge.
* @param {string} input.codeChallengeMethod - The PKCE method (e.g. S256).
* @param {string|null} [input.scope] - Granted scope.
* @param {string|Date} input.expiresAt - Expiration ISO string or Date.
* @returns {Promise<string>} The authorization code.
*/
return async ({
code,
clientId,
googleAuthId,
redirectUri,
codeChallenge,
codeChallengeMethod = 'S256',
scope = 'mcp:tools',
expiresAt,
}) => {
const exp = expiresAt instanceof Date ? expiresAt.toISOString() : expiresAt;
await provider.query(sql, {
code,
clientId,
googleAuthId,
redirectUri,
codeChallenge,
codeChallengeMethod,
scope,
expiresAt: exp,
});
return code;
};
}

View File

@@ -0,0 +1,34 @@
import { INSERT_REFRESH_TOKEN as MSSQL_INSERT } from '../../providers/mssql/queries/mcp.js';
import { INSERT_REFRESH_TOKEN as SQLITE_INSERT } from '../../providers/sqlite3/queries/mcp.js';
export default function createRefreshToken(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_INSERT : MSSQL_INSERT;
/**
* Stores an OAuth 2.1 refresh token.
*
* @param {object} input
* @param {string} input.refreshToken - The refresh token string.
* @param {string} input.clientId - The client ID.
* @param {number} input.googleAuthId - The user ID.
* @param {string|null} [input.scope] - Scopes granted.
* @param {string|Date} input.expiresAt - Expiration Date or ISO string.
* @returns {Promise<object>} Created token record or id.
*/
return async ({
refreshToken,
clientId,
googleAuthId,
scope = 'mcp:tools',
expiresAt,
}) => {
const exp = expiresAt instanceof Date ? expiresAt.toISOString() : expiresAt;
const result = await provider.query(sql, {
refreshToken,
clientId,
googleAuthId,
scope,
expiresAt: exp,
});
return result.rows[0]?.id ?? result.insertId;
};
}

View File

@@ -0,0 +1,16 @@
import { DELETE_CLIENT as MSSQL_DELETE } from '../../providers/mssql/queries/mcp.js';
import { DELETE_CLIENT as SQLITE_DELETE } from '../../providers/sqlite3/queries/mcp.js';
export default function deleteClient(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_DELETE : MSSQL_DELETE;
/**
* Deletes a registered MCP client by client ID.
*
* @param {string} clientId - The client identifier to delete.
* @returns {Promise<boolean>} True if deleted.
*/
return async (clientId) => {
await provider.query(sql, { clientId });
return true;
};
}

View File

@@ -0,0 +1,16 @@
import { GET_AUTH_CODE as MSSQL_GET } from '../../providers/mssql/queries/mcp.js';
import { GET_AUTH_CODE as SQLITE_GET } from '../../providers/sqlite3/queries/mcp.js';
export default function getAuthCode(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET;
/**
* Retrieves an authorization code record.
*
* @param {string} code - The authorization code.
* @returns {Promise<object|null>} The auth code record or null.
*/
return async (code) => {
const result = await provider.query(sql, { code });
return result.rows[0] ?? null;
};
}

View File

@@ -0,0 +1,16 @@
import { GET_CLIENT as MSSQL_GET } from '../../providers/mssql/queries/mcp.js';
import { GET_CLIENT as SQLITE_GET } from '../../providers/sqlite3/queries/mcp.js';
export default function getClient(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET;
/**
* Retrieves an MCP client by client ID.
*
* @param {string} clientId - The client identifier.
* @returns {Promise<object|null>} The client record or null if not found.
*/
return async (clientId) => {
const result = await provider.query(sql, { clientId });
return result.rows[0] ?? null;
};
}

View File

@@ -0,0 +1,16 @@
import { GET_REFRESH_TOKEN as MSSQL_GET } from '../../providers/mssql/queries/mcp.js';
import { GET_REFRESH_TOKEN as SQLITE_GET } from '../../providers/sqlite3/queries/mcp.js';
export default function getRefreshToken(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_GET : MSSQL_GET;
/**
* Retrieves an OAuth 2.1 refresh token.
*
* @param {string} refreshToken - The refresh token.
* @returns {Promise<object|null>} The refresh token record or null.
*/
return async (refreshToken) => {
const result = await provider.query(sql, { refreshToken });
return result.rows[0] ?? null;
};
}

View File

@@ -0,0 +1,15 @@
import { LIST_CLIENTS as MSSQL_LIST } from '../../providers/mssql/queries/mcp.js';
import { LIST_CLIENTS as SQLITE_LIST } from '../../providers/sqlite3/queries/mcp.js';
export default function listClients(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_LIST : MSSQL_LIST;
/**
* Lists all registered MCP clients.
*
* @returns {Promise<Array<object>>} List of client records.
*/
return async () => {
const result = await provider.query(sql);
return result.rows ?? [];
};
}

View File

@@ -0,0 +1,55 @@
import { INSERT_CLIENT as MSSQL_INSERT } from '../../providers/mssql/queries/mcp.js';
import { INSERT_CLIENT as SQLITE_INSERT } from '../../providers/sqlite3/queries/mcp.js';
export default function registerClient(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_INSERT : MSSQL_INSERT;
/**
* Registers a new OAuth MCP client.
*
* @param {object} input
* @param {string} input.clientId - Unique client identifier.
* @param {string|null} [input.clientSecret] - Optional client secret for confidential clients.
* @param {string} input.clientName - Human-readable client name.
* @param {string|Array<string>} input.redirectUris - JSON string or array of redirect URIs.
* @param {string|Array<string>} [input.grantTypes] - Supported grant types.
* @param {string|Array<string>} [input.responseTypes] - Supported response types.
* @param {string|null} [input.scope] - Allowed scope.
* @returns {Promise<object>} The created client record.
*/
return async ({
clientId,
clientSecret = null,
clientName,
redirectUris,
grantTypes = 'authorization_code,refresh_token',
responseTypes = 'code',
scope = 'mcp:tools',
}) => {
const urisStr = Array.isArray(redirectUris) ? JSON.stringify(redirectUris) : redirectUris;
const grantsStr = Array.isArray(grantTypes) ? grantTypes.join(',') : grantTypes;
const resTypesStr = Array.isArray(responseTypes) ? responseTypes.join(',') : responseTypes;
const result = await provider.query(sql, {
clientId,
clientSecret,
clientName,
redirectUris: urisStr,
grantTypes: grantsStr,
responseTypes: resTypesStr,
scope,
});
const row = result.rows[0];
return {
id: row?.id ?? result.insertId,
clientId: row?.clientId ?? row?.client_id ?? clientId,
clientSecret: row?.clientSecret ?? row?.client_secret ?? clientSecret,
clientName: row?.clientName ?? row?.client_name ?? clientName,
redirectUris: row?.redirectUris ?? row?.redirect_uris ?? urisStr,
grantTypes: row?.grantTypes ?? row?.grant_types ?? grantsStr,
responseTypes: row?.responseTypes ?? row?.response_types ?? resTypesStr,
scope: row?.scope ?? scope,
createdAt: row?.createdAt ?? row?.created_at,
};
};
}

View File

@@ -0,0 +1,16 @@
import { REVOKE_REFRESH_TOKEN as MSSQL_REVOKE } from '../../providers/mssql/queries/mcp.js';
import { REVOKE_REFRESH_TOKEN as SQLITE_REVOKE } from '../../providers/sqlite3/queries/mcp.js';
export default function revokeRefreshToken(provider) {
const sql = provider.dialect === 'sqlite3' ? SQLITE_REVOKE : MSSQL_REVOKE;
/**
* Revokes an OAuth 2.1 refresh token.
*
* @param {string} refreshToken - The refresh token to revoke.
* @returns {Promise<boolean>} True once revoked.
*/
return async (refreshToken) => {
await provider.query(sql, { refreshToken });
return true;
};
}

View File

@@ -34,7 +34,8 @@ export default function peekNumber(provider) {
*/
return async (companyId, type, tx) => {
const doPeek = async (runner) => {
await runner.query(ensureSql, { companyId, type });
const prefix = type === 'shipment' ? '-L-' : '';
await runner.query(ensureSql, { companyId, type, prefix });
const res = await runner.query(getSql, { companyId, type });
const row = res.rows[0];
if (!row) {