@codeguide/core 0.0.20 → 0.0.22

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/codeguide.ts CHANGED
@@ -16,6 +16,7 @@ import {
16
16
  SubscriptionService,
17
17
  CancellationFunnelService,
18
18
  CodespaceService,
19
+ ExternalTokenService,
19
20
  } from './services'
20
21
  import { APIServiceConfig, CodeGuideOptions } from './types'
21
22
 
@@ -29,6 +30,7 @@ export class CodeGuide {
29
30
  public subscription: SubscriptionService
30
31
  public cancellationFunnel: CancellationFunnelService
31
32
  public codespace: CodespaceService
33
+ public externalTokens: ExternalTokenService
32
34
  private options: CodeGuideOptions
33
35
 
34
36
  constructor(config: APIServiceConfig, options: CodeGuideOptions = {}) {
@@ -44,6 +46,7 @@ export class CodeGuide {
44
46
  this.subscription = new SubscriptionService(config)
45
47
  this.cancellationFunnel = new CancellationFunnelService(config)
46
48
  this.codespace = new CodespaceService(config)
49
+ this.externalTokens = new ExternalTokenService(config)
47
50
  }
48
51
 
49
52
  // Convenience method for backward compatibility
@@ -1,4 +1,4 @@
1
- import { GenerationService, ProjectService, UsageService, RepositoryAnalysisService, TaskService, ApiKeyEnhancedService, SubscriptionService, CancellationFunnelService, CodespaceService } from './services';
1
+ import { GenerationService, ProjectService, UsageService, RepositoryAnalysisService, TaskService, ApiKeyEnhancedService, SubscriptionService, CancellationFunnelService, CodespaceService, ExternalTokenService } from './services';
2
2
  import { APIServiceConfig, CodeGuideOptions } from './types';
3
3
  export declare class CodeGuide {
4
4
  generation: GenerationService;
@@ -10,6 +10,7 @@ export declare class CodeGuide {
10
10
  subscription: SubscriptionService;
11
11
  cancellationFunnel: CancellationFunnelService;
12
12
  codespace: CodespaceService;
13
+ externalTokens: ExternalTokenService;
13
14
  private options;
14
15
  constructor(config: APIServiceConfig, options?: CodeGuideOptions);
15
16
  getGuidance(prompt: string): Promise<any>;
package/dist/codeguide.js CHANGED
@@ -25,6 +25,7 @@ class CodeGuide {
25
25
  this.subscription = new services_1.SubscriptionService(config);
26
26
  this.cancellationFunnel = new services_1.CancellationFunnelService(config);
27
27
  this.codespace = new services_1.CodespaceService(config);
28
+ this.externalTokens = new services_1.ExternalTokenService(config);
28
29
  }
29
30
  // Convenience method for backward compatibility
30
31
  async getGuidance(prompt) {
package/dist/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export * from './services';
3
3
  export * from './types';
4
4
  export type { ConnectRepositoryRequest, ConnectRepositoryResponse } from './services/projects/project-types';
5
5
  export type { CreateCodespaceTaskRequestV2 as CreateCodespaceTaskRequest, CreateCodespaceTaskResponseV2 as CreateCodespaceTaskResponse, CreateBackgroundCodespaceTaskRequest, CreateBackgroundCodespaceTaskResponse, ModelApiKey, GetCodespaceTaskResponse, CodespaceTaskData, TechnicalDocument, GetProjectTasksByCodespaceResponse } from './services/codespace/codespace-types';
6
+ export type { StoreExternalTokenRequest, StoreExternalTokenResponse, ListTokensQuery, ListTokensResponse, ValidateTokenRequest, ValidateTokenResponse, FindBestMatchRequest, FindBestMatchResponse, Platform, TokenType } from './services/external-tokens/external-tokens-types';
@@ -0,0 +1,19 @@
1
+ import { BaseService } from '../base/base-service';
2
+ import { StoreExternalTokenRequest, StoreExternalTokenResponse, StoreWithDetectionRequest, StoreWithDetectionResponse, ListTokensQuery, ListTokensResponse, ValidateTokenRequest, ValidateTokenResponse, FindBestMatchRequest, FindBestMatchResponse, TestStoredTokenRequest, TestStoredTokenResponse, GetTokenResponse, UpdateTokenRequest, UpdateTokenResponse, RevokeTokenResponse, SupportedPlatformsResponse, StoreGitHubTokenRequest, StoreGitLabTokenRequest } from './external-tokens-types';
3
+ export declare class ExternalTokenService extends BaseService {
4
+ storeExternalToken(request: StoreExternalTokenRequest): Promise<StoreExternalTokenResponse>;
5
+ storeWithDetection(request: StoreWithDetectionRequest): Promise<StoreWithDetectionResponse>;
6
+ storeGitHubToken(request: StoreGitHubTokenRequest): Promise<StoreExternalTokenResponse>;
7
+ storeGitLabToken(request: StoreGitLabTokenRequest): Promise<StoreExternalTokenResponse>;
8
+ listTokens(query?: ListTokensQuery): Promise<ListTokensResponse>;
9
+ getToken(tokenId: string): Promise<GetTokenResponse>;
10
+ validateToken(request: ValidateTokenRequest): Promise<ValidateTokenResponse>;
11
+ findBestMatch(request: FindBestMatchRequest): Promise<FindBestMatchResponse>;
12
+ testStoredToken(tokenId: string, request: TestStoredTokenRequest): Promise<TestStoredTokenResponse>;
13
+ updateToken(tokenId: string, request: UpdateTokenRequest): Promise<UpdateTokenResponse>;
14
+ revokeToken(tokenId: string): Promise<RevokeTokenResponse>;
15
+ getSupportedPlatforms(): Promise<SupportedPlatformsResponse>;
16
+ private validateStoreRequest;
17
+ private validateTokenFormat;
18
+ private validateRepositoryUrlPattern;
19
+ }
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExternalTokenService = void 0;
4
+ const base_service_1 = require("../base/base-service");
5
+ class ExternalTokenService extends base_service_1.BaseService {
6
+ // Core Storage Endpoints
7
+ async storeExternalToken(request) {
8
+ this.validateStoreRequest(request);
9
+ return this.post('/external-tokens/store', request);
10
+ }
11
+ async storeWithDetection(request) {
12
+ if (!request.token) {
13
+ throw new Error('token is required');
14
+ }
15
+ if (!request.token_name) {
16
+ throw new Error('token_name is required');
17
+ }
18
+ return this.post('/external-tokens/store-with-detection', request);
19
+ }
20
+ // Platform-Specific Endpoints (Backward Compatible)
21
+ async storeGitHubToken(request) {
22
+ if (!request.token) {
23
+ throw new Error('token is required');
24
+ }
25
+ if (!request.token_name) {
26
+ throw new Error('token_name is required');
27
+ }
28
+ return this.post('/external-tokens/store/github', request);
29
+ }
30
+ async storeGitLabToken(request) {
31
+ if (!request.token) {
32
+ throw new Error('token is required');
33
+ }
34
+ if (!request.token_name) {
35
+ throw new Error('token_name is required');
36
+ }
37
+ return this.post('/external-tokens/store/gitlab', request);
38
+ }
39
+ // Retrieval Endpoints
40
+ async listTokens(query) {
41
+ const params = new URLSearchParams();
42
+ if (query?.platform) {
43
+ params.append('platform', query.platform);
44
+ }
45
+ if (query?.include_inactive !== undefined) {
46
+ params.append('include_inactive', query.include_inactive.toString());
47
+ }
48
+ if (query?.page) {
49
+ params.append('page', query.page.toString());
50
+ }
51
+ if (query?.per_page) {
52
+ params.append('per_page', query.per_page.toString());
53
+ }
54
+ const queryString = params.toString();
55
+ const url = queryString ? `/external-tokens/?${queryString}` : '/external-tokens/';
56
+ return this.get(url);
57
+ }
58
+ async getToken(tokenId) {
59
+ if (!tokenId) {
60
+ throw new Error('token_id is required');
61
+ }
62
+ return this.get(`/external-tokens/${tokenId}`);
63
+ }
64
+ // Validation and Testing Endpoints
65
+ async validateToken(request) {
66
+ if (!request.token) {
67
+ throw new Error('token is required');
68
+ }
69
+ return this.post('/external-tokens/validate', request);
70
+ }
71
+ async findBestMatch(request) {
72
+ if (!request.repository_url) {
73
+ throw new Error('repository_url is required');
74
+ }
75
+ return this.post('/external-tokens/find-best-match', request);
76
+ }
77
+ async testStoredToken(tokenId, request) {
78
+ if (!tokenId) {
79
+ throw new Error('token_id is required');
80
+ }
81
+ if (!request.repository_url) {
82
+ throw new Error('repository_url is required');
83
+ }
84
+ return this.post(`/external-tokens/${tokenId}/test`, request);
85
+ }
86
+ // Management Endpoints
87
+ async updateToken(tokenId, request) {
88
+ if (!tokenId) {
89
+ throw new Error('token_id is required');
90
+ }
91
+ return this.put(`/external-tokens/${tokenId}`, request);
92
+ }
93
+ async revokeToken(tokenId) {
94
+ if (!tokenId) {
95
+ throw new Error('token_id is required');
96
+ }
97
+ return this.delete(`/external-tokens/${tokenId}`);
98
+ }
99
+ // Platform Discovery Endpoint
100
+ async getSupportedPlatforms() {
101
+ return this.get('/external-tokens/platforms');
102
+ }
103
+ // Private validation methods
104
+ validateStoreRequest(request) {
105
+ if (!request.platform) {
106
+ throw new Error('platform is required');
107
+ }
108
+ if (!request.token) {
109
+ throw new Error('token is required');
110
+ }
111
+ if (!request.token_name) {
112
+ throw new Error('token_name is required');
113
+ }
114
+ if (!request.token_type) {
115
+ throw new Error('token_type is required');
116
+ }
117
+ // Validate platform
118
+ const validPlatforms = ['github', 'gitlab', 'bitbucket'];
119
+ if (!validPlatforms.includes(request.platform)) {
120
+ throw new Error(`platform must be one of: ${validPlatforms.join(', ')}`);
121
+ }
122
+ // Validate token format based on platform
123
+ this.validateTokenFormat(request.token, request.platform);
124
+ // Validate repository URL pattern if provided
125
+ if (request.repository_url_pattern) {
126
+ this.validateRepositoryUrlPattern(request.repository_url_pattern, request.platform);
127
+ }
128
+ // Validate expires_at if provided
129
+ if (request.expires_at) {
130
+ const expiresDate = new Date(request.expires_at);
131
+ if (isNaN(expiresDate.getTime())) {
132
+ throw new Error('expires_at must be a valid ISO 8601 date string');
133
+ }
134
+ if (expiresDate <= new Date()) {
135
+ throw new Error('expires_at must be in the future');
136
+ }
137
+ }
138
+ }
139
+ validateTokenFormat(token, platform) {
140
+ switch (platform) {
141
+ case 'github':
142
+ if (!token.startsWith('ghp_') && !token.startsWith('gho_') && !token.startsWith('ghu_') && !token.startsWith('ghs_') && !token.startsWith('ghr_')) {
143
+ throw new Error('Invalid GitHub token format. GitHub tokens should start with ghp_, gho_, ghu_, ghs_, or ghr_');
144
+ }
145
+ break;
146
+ case 'gitlab':
147
+ if (!token.startsWith('glpat-') && !token.startsWith('grlpat-') && !token.startsWith('gldt-')) {
148
+ throw new Error('Invalid GitLab token format. GitLab tokens should start with glpat-, grlpat-, or gldt-');
149
+ }
150
+ break;
151
+ case 'bitbucket':
152
+ if (!token.startsWith('ATBB')) {
153
+ throw new Error('Invalid Bitbucket token format. Bitbucket tokens should start with ATBB');
154
+ }
155
+ break;
156
+ }
157
+ }
158
+ validateRepositoryUrlPattern(pattern, platform) {
159
+ try {
160
+ new URL(pattern.replace('*', 'test'));
161
+ }
162
+ catch {
163
+ throw new Error('Invalid repository URL pattern');
164
+ }
165
+ // Check if pattern contains platform-specific domain
166
+ const platformDomains = {
167
+ github: ['github.com'],
168
+ gitlab: ['gitlab.com'],
169
+ bitbucket: ['bitbucket.org']
170
+ };
171
+ const hasValidDomain = platformDomains[platform].some(domain => pattern.includes(domain));
172
+ if (!hasValidDomain) {
173
+ throw new Error(`Repository URL pattern should contain ${platformDomains[platform].join(' or ')} for ${platform}`);
174
+ }
175
+ }
176
+ }
177
+ exports.ExternalTokenService = ExternalTokenService;
@@ -0,0 +1,168 @@
1
+ export type Platform = 'github' | 'gitlab' | 'bitbucket';
2
+ export type TokenType = 'personal_access_token' | 'deploy_token' | 'github_app' | 'oauth' | 'project_token' | 'group_token' | 'workspace_token' | 'repository_token';
3
+ export interface StoreExternalTokenRequest {
4
+ platform: Platform;
5
+ token: string;
6
+ token_name: string;
7
+ token_type: TokenType;
8
+ repository_url_pattern?: string;
9
+ scopes?: string[];
10
+ expires_at?: string;
11
+ metadata?: Record<string, any>;
12
+ }
13
+ export interface StoreExternalTokenResponse {
14
+ id: string;
15
+ user_id: string;
16
+ platform: Platform;
17
+ token_name: string;
18
+ token_type: TokenType;
19
+ repository_url_pattern?: string;
20
+ scopes: string[];
21
+ is_active: boolean;
22
+ last_used_at: string | null;
23
+ expires_at: string | null;
24
+ created_at: string;
25
+ updated_at: string;
26
+ metadata?: Record<string, any>;
27
+ token_preview: string;
28
+ }
29
+ export interface StoreWithDetectionRequest {
30
+ token: string;
31
+ token_name: string;
32
+ repository_url_pattern?: string;
33
+ scopes?: string[];
34
+ platform: Platform | null;
35
+ expires_at?: string;
36
+ metadata?: Record<string, any>;
37
+ }
38
+ export interface StoreWithDetectionResponse extends StoreExternalTokenResponse {
39
+ }
40
+ export interface ListTokensQuery {
41
+ platform?: Platform;
42
+ include_inactive?: boolean;
43
+ page?: number;
44
+ per_page?: number;
45
+ }
46
+ export interface ListTokensResponse {
47
+ tokens: Array<{
48
+ id: string;
49
+ platform: Platform;
50
+ token_name: string;
51
+ token_preview: string;
52
+ is_active: boolean;
53
+ created_at: string;
54
+ last_used_at?: string | null;
55
+ expires_at?: string | null;
56
+ }>;
57
+ total: number;
58
+ page: number;
59
+ per_page: number;
60
+ }
61
+ export interface ValidateTokenRequest {
62
+ token: string;
63
+ platform?: Platform | null;
64
+ }
65
+ export interface TokenUserInfo {
66
+ username: string;
67
+ id: number;
68
+ name?: string;
69
+ email?: string;
70
+ }
71
+ export interface ValidateTokenResponse {
72
+ valid: boolean;
73
+ platform: Platform | null;
74
+ token_type: TokenType | null;
75
+ scopes: string[];
76
+ user_info?: TokenUserInfo;
77
+ error_message: string | null;
78
+ }
79
+ export interface FindBestMatchRequest {
80
+ repository_url: string;
81
+ required_scopes?: string[];
82
+ preferred_platform?: Platform;
83
+ }
84
+ export interface AlternativeToken {
85
+ id: string;
86
+ platform: Platform;
87
+ token_name: string;
88
+ token_preview: string;
89
+ match_reason: string;
90
+ }
91
+ export interface FindBestMatchResponse {
92
+ token_found: boolean;
93
+ token?: {
94
+ id: string;
95
+ platform: Platform;
96
+ token_name: string;
97
+ token_preview: string;
98
+ };
99
+ match_reason?: string;
100
+ alternative_tokens: AlternativeToken[];
101
+ }
102
+ export interface TestStoredTokenRequest {
103
+ repository_url: string;
104
+ operation?: string;
105
+ }
106
+ export interface TestDetails {
107
+ platform: Platform;
108
+ token_id: string;
109
+ operation: string;
110
+ test_timestamp: string;
111
+ }
112
+ export interface TestStoredTokenResponse {
113
+ success: boolean;
114
+ message: string;
115
+ test_details: TestDetails;
116
+ recommendations?: string[];
117
+ }
118
+ export interface GetTokenResponse extends StoreExternalTokenResponse {
119
+ }
120
+ export interface UpdateTokenRequest {
121
+ token_name?: string;
122
+ repository_url_pattern?: string;
123
+ scopes?: string[];
124
+ is_active?: boolean;
125
+ expires_at?: string;
126
+ metadata?: Record<string, any>;
127
+ }
128
+ export interface UpdateTokenResponse extends StoreExternalTokenResponse {
129
+ }
130
+ export interface RevokeTokenResponse {
131
+ success: boolean;
132
+ message: string;
133
+ revoked_at: string;
134
+ }
135
+ export interface PlatformScopes {
136
+ [key: string]: string[];
137
+ }
138
+ export interface PlatformInfo {
139
+ name: string;
140
+ token_types: TokenType[];
141
+ api_base_url: string;
142
+ supported_scopes: PlatformScopes;
143
+ }
144
+ export interface SupportedPlatformsResponse {
145
+ platforms: {
146
+ github: PlatformInfo;
147
+ gitlab: PlatformInfo;
148
+ bitbucket: PlatformInfo;
149
+ };
150
+ total_count: number;
151
+ features: string[];
152
+ }
153
+ export interface StoreGitHubTokenRequest {
154
+ token: string;
155
+ token_name: string;
156
+ repository_url_pattern?: string;
157
+ scopes?: string[];
158
+ expires_at?: string;
159
+ metadata?: Record<string, any>;
160
+ }
161
+ export interface StoreGitLabTokenRequest {
162
+ token: string;
163
+ token_name: string;
164
+ repository_url_pattern?: string;
165
+ scopes?: string[];
166
+ expires_at?: string;
167
+ metadata?: Record<string, any>;
168
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,2 @@
1
+ export { ExternalTokenService } from './external-tokens-service';
2
+ export * from './external-tokens-types';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.ExternalTokenService = void 0;
18
+ var external_tokens_service_1 = require("./external-tokens-service");
19
+ Object.defineProperty(exports, "ExternalTokenService", { enumerable: true, get: function () { return external_tokens_service_1.ExternalTokenService; } });
20
+ __exportStar(require("./external-tokens-types"), exports);
@@ -8,6 +8,7 @@ export { ApiKeyEnhancedService } from './api-key-enhanced';
8
8
  export { SubscriptionService } from './subscriptions';
9
9
  export { CancellationFunnelService } from './cancellation-funnel';
10
10
  export { CodespaceService } from './codespace';
11
+ export { ExternalTokenService } from './external-tokens';
11
12
  export * from './generation';
12
13
  export * from './projects';
13
14
  export * from './usage';
@@ -17,3 +18,4 @@ export * from './api-key-enhanced';
17
18
  export * from './subscriptions';
18
19
  export * from './cancellation-funnel';
19
20
  export * from './codespace';
21
+ export * from './external-tokens';
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.CodespaceService = exports.CancellationFunnelService = exports.SubscriptionService = exports.ApiKeyEnhancedService = exports.TaskService = exports.RepositoryAnalysisService = exports.UsageService = exports.ProjectService = exports.GenerationService = exports.BaseService = void 0;
20
+ exports.ExternalTokenService = exports.CodespaceService = exports.CancellationFunnelService = exports.SubscriptionService = exports.ApiKeyEnhancedService = exports.TaskService = exports.RepositoryAnalysisService = exports.UsageService = exports.ProjectService = exports.GenerationService = exports.BaseService = void 0;
21
21
  const dotenv_1 = __importDefault(require("dotenv"));
22
22
  const path_1 = __importDefault(require("path"));
23
23
  // Load environment variables from project root
@@ -45,6 +45,8 @@ var cancellation_funnel_1 = require("./cancellation-funnel");
45
45
  Object.defineProperty(exports, "CancellationFunnelService", { enumerable: true, get: function () { return cancellation_funnel_1.CancellationFunnelService; } });
46
46
  var codespace_1 = require("./codespace");
47
47
  Object.defineProperty(exports, "CodespaceService", { enumerable: true, get: function () { return codespace_1.CodespaceService; } });
48
+ var external_tokens_1 = require("./external-tokens");
49
+ Object.defineProperty(exports, "ExternalTokenService", { enumerable: true, get: function () { return external_tokens_1.ExternalTokenService; } });
48
50
  // Re-export all types for convenience
49
51
  __exportStar(require("./generation"), exports);
50
52
  __exportStar(require("./projects"), exports);
@@ -55,3 +57,4 @@ __exportStar(require("./api-key-enhanced"), exports);
55
57
  __exportStar(require("./subscriptions"), exports);
56
58
  __exportStar(require("./cancellation-funnel"), exports);
57
59
  __exportStar(require("./codespace"), exports);
60
+ __exportStar(require("./external-tokens"), exports);
package/index.ts CHANGED
@@ -24,3 +24,17 @@ export type {
24
24
  TechnicalDocument,
25
25
  GetProjectTasksByCodespaceResponse
26
26
  } from './services/codespace/codespace-types'
27
+
28
+ // Export commonly used external tokens types for convenience
29
+ export type {
30
+ StoreExternalTokenRequest,
31
+ StoreExternalTokenResponse,
32
+ ListTokensQuery,
33
+ ListTokensResponse,
34
+ ValidateTokenRequest,
35
+ ValidateTokenResponse,
36
+ FindBestMatchRequest,
37
+ FindBestMatchResponse,
38
+ Platform,
39
+ TokenType
40
+ } from './services/external-tokens/external-tokens-types'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeguide/core",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Core package for code guidance with programmatic API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -0,0 +1,231 @@
1
+ import { BaseService } from '../base/base-service'
2
+ import {
3
+ StoreExternalTokenRequest,
4
+ StoreExternalTokenResponse,
5
+ StoreWithDetectionRequest,
6
+ StoreWithDetectionResponse,
7
+ ListTokensQuery,
8
+ ListTokensResponse,
9
+ ValidateTokenRequest,
10
+ ValidateTokenResponse,
11
+ FindBestMatchRequest,
12
+ FindBestMatchResponse,
13
+ TestStoredTokenRequest,
14
+ TestStoredTokenResponse,
15
+ GetTokenResponse,
16
+ UpdateTokenRequest,
17
+ UpdateTokenResponse,
18
+ RevokeTokenResponse,
19
+ SupportedPlatformsResponse,
20
+ StoreGitHubTokenRequest,
21
+ StoreGitLabTokenRequest,
22
+ Platform,
23
+ } from './external-tokens-types'
24
+
25
+ export class ExternalTokenService extends BaseService {
26
+ // Core Storage Endpoints
27
+
28
+ async storeExternalToken(request: StoreExternalTokenRequest): Promise<StoreExternalTokenResponse> {
29
+ this.validateStoreRequest(request)
30
+ return this.post<StoreExternalTokenResponse>('/external-tokens/store', request)
31
+ }
32
+
33
+ async storeWithDetection(request: StoreWithDetectionRequest): Promise<StoreWithDetectionResponse> {
34
+ if (!request.token) {
35
+ throw new Error('token is required')
36
+ }
37
+ if (!request.token_name) {
38
+ throw new Error('token_name is required')
39
+ }
40
+ return this.post<StoreWithDetectionResponse>('/external-tokens/store-with-detection', request)
41
+ }
42
+
43
+ // Platform-Specific Endpoints (Backward Compatible)
44
+
45
+ async storeGitHubToken(request: StoreGitHubTokenRequest): Promise<StoreExternalTokenResponse> {
46
+ if (!request.token) {
47
+ throw new Error('token is required')
48
+ }
49
+ if (!request.token_name) {
50
+ throw new Error('token_name is required')
51
+ }
52
+ return this.post<StoreExternalTokenResponse>('/external-tokens/store/github', request)
53
+ }
54
+
55
+ async storeGitLabToken(request: StoreGitLabTokenRequest): Promise<StoreExternalTokenResponse> {
56
+ if (!request.token) {
57
+ throw new Error('token is required')
58
+ }
59
+ if (!request.token_name) {
60
+ throw new Error('token_name is required')
61
+ }
62
+ return this.post<StoreExternalTokenResponse>('/external-tokens/store/gitlab', request)
63
+ }
64
+
65
+ // Retrieval Endpoints
66
+
67
+ async listTokens(query?: ListTokensQuery): Promise<ListTokensResponse> {
68
+ const params = new URLSearchParams()
69
+
70
+ if (query?.platform) {
71
+ params.append('platform', query.platform)
72
+ }
73
+ if (query?.include_inactive !== undefined) {
74
+ params.append('include_inactive', query.include_inactive.toString())
75
+ }
76
+ if (query?.page) {
77
+ params.append('page', query.page.toString())
78
+ }
79
+ if (query?.per_page) {
80
+ params.append('per_page', query.per_page.toString())
81
+ }
82
+
83
+ const queryString = params.toString()
84
+ const url = queryString ? `/external-tokens/?${queryString}` : '/external-tokens/'
85
+
86
+ return this.get<ListTokensResponse>(url)
87
+ }
88
+
89
+ async getToken(tokenId: string): Promise<GetTokenResponse> {
90
+ if (!tokenId) {
91
+ throw new Error('token_id is required')
92
+ }
93
+ return this.get<GetTokenResponse>(`/external-tokens/${tokenId}`)
94
+ }
95
+
96
+ // Validation and Testing Endpoints
97
+
98
+ async validateToken(request: ValidateTokenRequest): Promise<ValidateTokenResponse> {
99
+ if (!request.token) {
100
+ throw new Error('token is required')
101
+ }
102
+ return this.post<ValidateTokenResponse>('/external-tokens/validate', request)
103
+ }
104
+
105
+ async findBestMatch(request: FindBestMatchRequest): Promise<FindBestMatchResponse> {
106
+ if (!request.repository_url) {
107
+ throw new Error('repository_url is required')
108
+ }
109
+ return this.post<FindBestMatchResponse>('/external-tokens/find-best-match', request)
110
+ }
111
+
112
+ async testStoredToken(tokenId: string, request: TestStoredTokenRequest): Promise<TestStoredTokenResponse> {
113
+ if (!tokenId) {
114
+ throw new Error('token_id is required')
115
+ }
116
+ if (!request.repository_url) {
117
+ throw new Error('repository_url is required')
118
+ }
119
+ return this.post<TestStoredTokenResponse>(`/external-tokens/${tokenId}/test`, request)
120
+ }
121
+
122
+ // Management Endpoints
123
+
124
+ async updateToken(tokenId: string, request: UpdateTokenRequest): Promise<UpdateTokenResponse> {
125
+ if (!tokenId) {
126
+ throw new Error('token_id is required')
127
+ }
128
+ return this.put<UpdateTokenResponse>(`/external-tokens/${tokenId}`, request)
129
+ }
130
+
131
+ async revokeToken(tokenId: string): Promise<RevokeTokenResponse> {
132
+ if (!tokenId) {
133
+ throw new Error('token_id is required')
134
+ }
135
+ return this.delete<RevokeTokenResponse>(`/external-tokens/${tokenId}`)
136
+ }
137
+
138
+ // Platform Discovery Endpoint
139
+
140
+ async getSupportedPlatforms(): Promise<SupportedPlatformsResponse> {
141
+ return this.get<SupportedPlatformsResponse>('/external-tokens/platforms')
142
+ }
143
+
144
+ // Private validation methods
145
+
146
+ private validateStoreRequest(request: StoreExternalTokenRequest): void {
147
+ if (!request.platform) {
148
+ throw new Error('platform is required')
149
+ }
150
+
151
+ if (!request.token) {
152
+ throw new Error('token is required')
153
+ }
154
+
155
+ if (!request.token_name) {
156
+ throw new Error('token_name is required')
157
+ }
158
+
159
+ if (!request.token_type) {
160
+ throw new Error('token_type is required')
161
+ }
162
+
163
+ // Validate platform
164
+ const validPlatforms: Platform[] = ['github', 'gitlab', 'bitbucket']
165
+ if (!validPlatforms.includes(request.platform)) {
166
+ throw new Error(`platform must be one of: ${validPlatforms.join(', ')}`)
167
+ }
168
+
169
+ // Validate token format based on platform
170
+ this.validateTokenFormat(request.token, request.platform)
171
+
172
+ // Validate repository URL pattern if provided
173
+ if (request.repository_url_pattern) {
174
+ this.validateRepositoryUrlPattern(request.repository_url_pattern, request.platform)
175
+ }
176
+
177
+ // Validate expires_at if provided
178
+ if (request.expires_at) {
179
+ const expiresDate = new Date(request.expires_at)
180
+ if (isNaN(expiresDate.getTime())) {
181
+ throw new Error('expires_at must be a valid ISO 8601 date string')
182
+ }
183
+ if (expiresDate <= new Date()) {
184
+ throw new Error('expires_at must be in the future')
185
+ }
186
+ }
187
+ }
188
+
189
+ private validateTokenFormat(token: string, platform: Platform): void {
190
+ switch (platform) {
191
+ case 'github':
192
+ if (!token.startsWith('ghp_') && !token.startsWith('gho_') && !token.startsWith('ghu_') && !token.startsWith('ghs_') && !token.startsWith('ghr_')) {
193
+ throw new Error('Invalid GitHub token format. GitHub tokens should start with ghp_, gho_, ghu_, ghs_, or ghr_')
194
+ }
195
+ break
196
+ case 'gitlab':
197
+ if (!token.startsWith('glpat-') && !token.startsWith('grlpat-') && !token.startsWith('gldt-')) {
198
+ throw new Error('Invalid GitLab token format. GitLab tokens should start with glpat-, grlpat-, or gldt-')
199
+ }
200
+ break
201
+ case 'bitbucket':
202
+ if (!token.startsWith('ATBB')) {
203
+ throw new Error('Invalid Bitbucket token format. Bitbucket tokens should start with ATBB')
204
+ }
205
+ break
206
+ }
207
+ }
208
+
209
+ private validateRepositoryUrlPattern(pattern: string, platform: Platform): void {
210
+ try {
211
+ new URL(pattern.replace('*', 'test'))
212
+ } catch {
213
+ throw new Error('Invalid repository URL pattern')
214
+ }
215
+
216
+ // Check if pattern contains platform-specific domain
217
+ const platformDomains = {
218
+ github: ['github.com'],
219
+ gitlab: ['gitlab.com'],
220
+ bitbucket: ['bitbucket.org']
221
+ }
222
+
223
+ const hasValidDomain = platformDomains[platform].some(domain =>
224
+ pattern.includes(domain)
225
+ )
226
+
227
+ if (!hasValidDomain) {
228
+ throw new Error(`Repository URL pattern should contain ${platformDomains[platform].join(' or ')} for ${platform}`)
229
+ }
230
+ }
231
+ }
@@ -0,0 +1,190 @@
1
+ export type Platform = 'github' | 'gitlab' | 'bitbucket'
2
+ export type TokenType = 'personal_access_token' | 'deploy_token' | 'github_app' | 'oauth' | 'project_token' | 'group_token' | 'workspace_token' | 'repository_token'
3
+
4
+ export interface StoreExternalTokenRequest {
5
+ platform: Platform
6
+ token: string
7
+ token_name: string
8
+ token_type: TokenType
9
+ repository_url_pattern?: string
10
+ scopes?: string[]
11
+ expires_at?: string
12
+ metadata?: Record<string, any>
13
+ }
14
+
15
+ export interface StoreExternalTokenResponse {
16
+ id: string
17
+ user_id: string
18
+ platform: Platform
19
+ token_name: string
20
+ token_type: TokenType
21
+ repository_url_pattern?: string
22
+ scopes: string[]
23
+ is_active: boolean
24
+ last_used_at: string | null
25
+ expires_at: string | null
26
+ created_at: string
27
+ updated_at: string
28
+ metadata?: Record<string, any>
29
+ token_preview: string
30
+ }
31
+
32
+ export interface StoreWithDetectionRequest {
33
+ token: string
34
+ token_name: string
35
+ repository_url_pattern?: string
36
+ scopes?: string[]
37
+ platform: Platform | null
38
+ expires_at?: string
39
+ metadata?: Record<string, any>
40
+ }
41
+
42
+ export interface StoreWithDetectionResponse extends StoreExternalTokenResponse {}
43
+
44
+ export interface ListTokensQuery {
45
+ platform?: Platform
46
+ include_inactive?: boolean
47
+ page?: number
48
+ per_page?: number
49
+ }
50
+
51
+ export interface ListTokensResponse {
52
+ tokens: Array<{
53
+ id: string
54
+ platform: Platform
55
+ token_name: string
56
+ token_preview: string
57
+ is_active: boolean
58
+ created_at: string
59
+ last_used_at?: string | null
60
+ expires_at?: string | null
61
+ }>
62
+ total: number
63
+ page: number
64
+ per_page: number
65
+ }
66
+
67
+ export interface ValidateTokenRequest {
68
+ token: string
69
+ platform?: Platform | null
70
+ }
71
+
72
+ export interface TokenUserInfo {
73
+ username: string
74
+ id: number
75
+ name?: string
76
+ email?: string
77
+ }
78
+
79
+ export interface ValidateTokenResponse {
80
+ valid: boolean
81
+ platform: Platform | null
82
+ token_type: TokenType | null
83
+ scopes: string[]
84
+ user_info?: TokenUserInfo
85
+ error_message: string | null
86
+ }
87
+
88
+ export interface FindBestMatchRequest {
89
+ repository_url: string
90
+ required_scopes?: string[]
91
+ preferred_platform?: Platform
92
+ }
93
+
94
+ export interface AlternativeToken {
95
+ id: string
96
+ platform: Platform
97
+ token_name: string
98
+ token_preview: string
99
+ match_reason: string
100
+ }
101
+
102
+ export interface FindBestMatchResponse {
103
+ token_found: boolean
104
+ token?: {
105
+ id: string
106
+ platform: Platform
107
+ token_name: string
108
+ token_preview: string
109
+ }
110
+ match_reason?: string
111
+ alternative_tokens: AlternativeToken[]
112
+ }
113
+
114
+ export interface TestStoredTokenRequest {
115
+ repository_url: string
116
+ operation?: string
117
+ }
118
+
119
+ export interface TestDetails {
120
+ platform: Platform
121
+ token_id: string
122
+ operation: string
123
+ test_timestamp: string
124
+ }
125
+
126
+ export interface TestStoredTokenResponse {
127
+ success: boolean
128
+ message: string
129
+ test_details: TestDetails
130
+ recommendations?: string[]
131
+ }
132
+
133
+ export interface GetTokenResponse extends StoreExternalTokenResponse {}
134
+
135
+ export interface UpdateTokenRequest {
136
+ token_name?: string
137
+ repository_url_pattern?: string
138
+ scopes?: string[]
139
+ is_active?: boolean
140
+ expires_at?: string
141
+ metadata?: Record<string, any>
142
+ }
143
+
144
+ export interface UpdateTokenResponse extends StoreExternalTokenResponse {}
145
+
146
+ export interface RevokeTokenResponse {
147
+ success: boolean
148
+ message: string
149
+ revoked_at: string
150
+ }
151
+
152
+ export interface PlatformScopes {
153
+ [key: string]: string[]
154
+ }
155
+
156
+ export interface PlatformInfo {
157
+ name: string
158
+ token_types: TokenType[]
159
+ api_base_url: string
160
+ supported_scopes: PlatformScopes
161
+ }
162
+
163
+ export interface SupportedPlatformsResponse {
164
+ platforms: {
165
+ github: PlatformInfo
166
+ gitlab: PlatformInfo
167
+ bitbucket: PlatformInfo
168
+ }
169
+ total_count: number
170
+ features: string[]
171
+ }
172
+
173
+ // Platform-specific store requests for backward compatibility
174
+ export interface StoreGitHubTokenRequest {
175
+ token: string
176
+ token_name: string
177
+ repository_url_pattern?: string
178
+ scopes?: string[]
179
+ expires_at?: string
180
+ metadata?: Record<string, any>
181
+ }
182
+
183
+ export interface StoreGitLabTokenRequest {
184
+ token: string
185
+ token_name: string
186
+ repository_url_pattern?: string
187
+ scopes?: string[]
188
+ expires_at?: string
189
+ metadata?: Record<string, any>
190
+ }
@@ -0,0 +1,2 @@
1
+ export { ExternalTokenService } from './external-tokens-service'
2
+ export * from './external-tokens-types'
package/services/index.ts CHANGED
@@ -17,6 +17,7 @@ export { ApiKeyEnhancedService } from './api-key-enhanced'
17
17
  export { SubscriptionService } from './subscriptions'
18
18
  export { CancellationFunnelService } from './cancellation-funnel'
19
19
  export { CodespaceService } from './codespace'
20
+ export { ExternalTokenService } from './external-tokens'
20
21
 
21
22
  // Re-export all types for convenience
22
23
  export * from './generation'
@@ -28,3 +29,4 @@ export * from './api-key-enhanced'
28
29
  export * from './subscriptions'
29
30
  export * from './cancellation-funnel'
30
31
  export * from './codespace'
32
+ export * from './external-tokens'