hale-commenting-system 2.2.0 → 2.2.2
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/.claude/settings.local.json +7 -0
- package/.editorconfig +17 -0
- package/.eslintrc.js +75 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
- package/.github/workflows/ci.yaml +51 -0
- package/.prettierignore +1 -0
- package/.prettierrc +4 -0
- package/GITHUB_OAUTH_ENV_TEMPLATE.md +53 -0
- package/LICENSE +21 -0
- package/README.md +92 -21
- package/package.json +74 -50
- package/scripts/README.md +42 -0
- package/scripts/integrate.js +472 -0
- package/src/app/AppLayout/AppLayout.tsx +248 -0
- package/src/app/Comments/Comments.tsx +273 -0
- package/src/app/Dashboard/Dashboard.tsx +10 -0
- package/src/app/NotFound/NotFound.tsx +35 -0
- package/src/app/Settings/General/GeneralSettings.tsx +16 -0
- package/src/app/Settings/Profile/ProfileSettings.tsx +18 -0
- package/src/app/Support/Support.tsx +50 -0
- package/src/app/__snapshots__/app.test.tsx.snap +524 -0
- package/src/app/app.css +11 -0
- package/src/app/app.test.tsx +55 -0
- package/src/app/bgimages/Patternfly-Logo.svg +28 -0
- package/src/app/commenting-system/components/CommentOverlay.tsx +93 -0
- package/src/app/commenting-system/components/CommentPanel.tsx +534 -0
- package/src/app/commenting-system/components/CommentPin.tsx +60 -0
- package/src/app/commenting-system/components/DetailsTab.tsx +516 -0
- package/src/app/commenting-system/components/FloatingWidget.tsx +130 -0
- package/src/app/commenting-system/components/JiraTab.tsx +696 -0
- package/src/app/commenting-system/contexts/CommentContext.tsx +1033 -0
- package/src/app/commenting-system/contexts/GitHubAuthContext.tsx +84 -0
- package/{dist/index.d.ts → src/app/commenting-system/index.ts} +5 -4
- package/src/app/commenting-system/services/githubAdapter.ts +359 -0
- package/src/app/commenting-system/types/index.ts +27 -0
- package/src/app/commenting-system/utils/version.ts +19 -0
- package/src/app/index.tsx +22 -0
- package/src/app/routes.tsx +81 -0
- package/src/app/utils/useDocumentTitle.ts +13 -0
- package/src/favicon.png +0 -0
- package/src/index.html +18 -0
- package/src/index.tsx +25 -0
- package/src/test/setup.ts +33 -0
- package/src/typings.d.ts +12 -0
- package/stylePaths.js +14 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +19 -0
- package/webpack.common.js +139 -0
- package/webpack.dev.js +318 -0
- package/webpack.prod.js +38 -0
- package/bin/detect.d.ts +0 -10
- package/bin/detect.js +0 -134
- package/bin/generators.d.ts +0 -20
- package/bin/generators.js +0 -272
- package/bin/hale-commenting.js +0 -4
- package/bin/index.d.ts +0 -2
- package/bin/index.js +0 -61
- package/bin/onboarding.d.ts +0 -1
- package/bin/onboarding.js +0 -395
- package/bin/postinstall.d.ts +0 -2
- package/bin/postinstall.js +0 -65
- package/bin/validators.d.ts +0 -2
- package/bin/validators.js +0 -66
- package/dist/cli/detect.d.ts +0 -10
- package/dist/cli/detect.js +0 -134
- package/dist/cli/generators.d.ts +0 -20
- package/dist/cli/generators.js +0 -272
- package/dist/cli/index.d.ts +0 -2
- package/dist/cli/index.js +0 -61
- package/dist/cli/onboarding.d.ts +0 -1
- package/dist/cli/onboarding.js +0 -395
- package/dist/cli/postinstall.d.ts +0 -2
- package/dist/cli/postinstall.js +0 -65
- package/dist/cli/validators.d.ts +0 -2
- package/dist/cli/validators.js +0 -66
- package/dist/components/CommentOverlay.d.ts +0 -2
- package/dist/components/CommentOverlay.js +0 -101
- package/dist/components/CommentPanel.d.ts +0 -6
- package/dist/components/CommentPanel.js +0 -334
- package/dist/components/CommentPin.d.ts +0 -11
- package/dist/components/CommentPin.js +0 -64
- package/dist/components/DetailsTab.d.ts +0 -2
- package/dist/components/DetailsTab.js +0 -380
- package/dist/components/FloatingWidget.d.ts +0 -8
- package/dist/components/FloatingWidget.js +0 -128
- package/dist/components/JiraTab.d.ts +0 -2
- package/dist/components/JiraTab.js +0 -507
- package/dist/contexts/CommentContext.d.ts +0 -30
- package/dist/contexts/CommentContext.js +0 -891
- package/dist/contexts/GitHubAuthContext.d.ts +0 -13
- package/dist/contexts/GitHubAuthContext.js +0 -96
- package/dist/index.js +0 -27
- package/dist/services/githubAdapter.d.ts +0 -56
- package/dist/services/githubAdapter.js +0 -321
- package/dist/types/index.d.ts +0 -25
- package/dist/types/index.js +0 -2
- package/dist/utils/version.d.ts +0 -1
- package/dist/utils/version.js +0 -23
- package/templates/webpack-middleware.js +0 -226
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { GitHubUser } from '../services/githubAdapter';
|
|
3
|
-
interface GitHubAuthContextType {
|
|
4
|
-
user: GitHubUser | null;
|
|
5
|
-
isAuthenticated: boolean;
|
|
6
|
-
login: () => void;
|
|
7
|
-
logout: () => void;
|
|
8
|
-
}
|
|
9
|
-
export declare const GitHubAuthProvider: React.FunctionComponent<{
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
}>;
|
|
12
|
-
export declare const useGitHubAuth: () => GitHubAuthContextType;
|
|
13
|
-
export {};
|
|
@@ -1,96 +0,0 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.useGitHubAuth = exports.GitHubAuthProvider = void 0;
|
|
37
|
-
const React = __importStar(require("react"));
|
|
38
|
-
const githubAdapter_1 = require("../services/githubAdapter");
|
|
39
|
-
const GitHubAuthContext = React.createContext(undefined);
|
|
40
|
-
const GitHubAuthProvider = ({ children }) => {
|
|
41
|
-
const [user, setUser] = React.useState(null);
|
|
42
|
-
React.useEffect(() => {
|
|
43
|
-
const stored = (0, githubAdapter_1.getStoredUser)();
|
|
44
|
-
if (stored)
|
|
45
|
-
setUser(stored);
|
|
46
|
-
}, []);
|
|
47
|
-
// Handle local dev OAuth callback via hash: /#/auth-callback?token=...&login=...&avatar=...
|
|
48
|
-
React.useEffect(() => {
|
|
49
|
-
const hash = window.location.hash;
|
|
50
|
-
if (!hash.includes('#/auth-callback'))
|
|
51
|
-
return;
|
|
52
|
-
const query = hash.split('?')[1] || '';
|
|
53
|
-
const params = new URLSearchParams(query);
|
|
54
|
-
const token = params.get('token');
|
|
55
|
-
const login = params.get('login');
|
|
56
|
-
const avatar = params.get('avatar');
|
|
57
|
-
if (token && login && avatar) {
|
|
58
|
-
const decodedUser = { login, avatar: decodeURIComponent(avatar) };
|
|
59
|
-
(0, githubAdapter_1.storeGitHubAuth)(token, decodedUser);
|
|
60
|
-
setUser(decodedUser);
|
|
61
|
-
}
|
|
62
|
-
// remove hash and return to home
|
|
63
|
-
window.location.hash = '/';
|
|
64
|
-
}, []);
|
|
65
|
-
const login = () => {
|
|
66
|
-
const clientId = process.env.VITE_GITHUB_CLIENT_ID;
|
|
67
|
-
if (!clientId) {
|
|
68
|
-
// eslint-disable-next-line no-alert
|
|
69
|
-
alert('GitHub login is not configured (missing VITE_GITHUB_CLIENT_ID).');
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const redirectUri = `${window.location.origin}/api/github-oauth-callback`;
|
|
73
|
-
// Use 'repo' scope for full access (works with both public and private repos)
|
|
74
|
-
// Use 'public_repo' only if you only need public repo access
|
|
75
|
-
const scope = 'repo';
|
|
76
|
-
const url = `https://github.com/login/oauth/authorize?client_id=${encodeURIComponent(clientId)}` +
|
|
77
|
-
`&redirect_uri=${encodeURIComponent(redirectUri)}` +
|
|
78
|
-
`&scope=${encodeURIComponent(scope)}`;
|
|
79
|
-
console.log('🔑 GitHub OAuth URL:', url);
|
|
80
|
-
console.log('📋 Scope requested:', scope);
|
|
81
|
-
window.location.href = url;
|
|
82
|
-
};
|
|
83
|
-
const logout = () => {
|
|
84
|
-
(0, githubAdapter_1.clearGitHubAuth)();
|
|
85
|
-
setUser(null);
|
|
86
|
-
};
|
|
87
|
-
return (React.createElement(GitHubAuthContext.Provider, { value: { user, isAuthenticated: !!user, login, logout } }, children));
|
|
88
|
-
};
|
|
89
|
-
exports.GitHubAuthProvider = GitHubAuthProvider;
|
|
90
|
-
const useGitHubAuth = () => {
|
|
91
|
-
const ctx = React.useContext(GitHubAuthContext);
|
|
92
|
-
if (!ctx)
|
|
93
|
-
throw new Error('useGitHubAuth must be used within a GitHubAuthProvider');
|
|
94
|
-
return ctx;
|
|
95
|
-
};
|
|
96
|
-
exports.useGitHubAuth = useGitHubAuth;
|
package/dist/index.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isGitHubConfigured = exports.githubAdapter = exports.FloatingWidget = exports.JiraTab = exports.DetailsTab = exports.CommentPanel = exports.CommentPin = exports.CommentOverlay = exports.useGitHubAuth = exports.GitHubAuthProvider = exports.useComments = exports.CommentProvider = void 0;
|
|
4
|
-
// Contexts
|
|
5
|
-
var CommentContext_1 = require("./contexts/CommentContext");
|
|
6
|
-
Object.defineProperty(exports, "CommentProvider", { enumerable: true, get: function () { return CommentContext_1.CommentProvider; } });
|
|
7
|
-
Object.defineProperty(exports, "useComments", { enumerable: true, get: function () { return CommentContext_1.useComments; } });
|
|
8
|
-
var GitHubAuthContext_1 = require("./contexts/GitHubAuthContext");
|
|
9
|
-
Object.defineProperty(exports, "GitHubAuthProvider", { enumerable: true, get: function () { return GitHubAuthContext_1.GitHubAuthProvider; } });
|
|
10
|
-
Object.defineProperty(exports, "useGitHubAuth", { enumerable: true, get: function () { return GitHubAuthContext_1.useGitHubAuth; } });
|
|
11
|
-
// Components
|
|
12
|
-
var CommentOverlay_1 = require("./components/CommentOverlay");
|
|
13
|
-
Object.defineProperty(exports, "CommentOverlay", { enumerable: true, get: function () { return CommentOverlay_1.CommentOverlay; } });
|
|
14
|
-
var CommentPin_1 = require("./components/CommentPin");
|
|
15
|
-
Object.defineProperty(exports, "CommentPin", { enumerable: true, get: function () { return CommentPin_1.CommentPin; } });
|
|
16
|
-
var CommentPanel_1 = require("./components/CommentPanel");
|
|
17
|
-
Object.defineProperty(exports, "CommentPanel", { enumerable: true, get: function () { return CommentPanel_1.CommentPanel; } });
|
|
18
|
-
var DetailsTab_1 = require("./components/DetailsTab");
|
|
19
|
-
Object.defineProperty(exports, "DetailsTab", { enumerable: true, get: function () { return DetailsTab_1.DetailsTab; } });
|
|
20
|
-
var JiraTab_1 = require("./components/JiraTab");
|
|
21
|
-
Object.defineProperty(exports, "JiraTab", { enumerable: true, get: function () { return JiraTab_1.JiraTab; } });
|
|
22
|
-
var FloatingWidget_1 = require("./components/FloatingWidget");
|
|
23
|
-
Object.defineProperty(exports, "FloatingWidget", { enumerable: true, get: function () { return FloatingWidget_1.FloatingWidget; } });
|
|
24
|
-
// Services
|
|
25
|
-
var githubAdapter_1 = require("./services/githubAdapter");
|
|
26
|
-
Object.defineProperty(exports, "githubAdapter", { enumerable: true, get: function () { return githubAdapter_1.githubAdapter; } });
|
|
27
|
-
Object.defineProperty(exports, "isGitHubConfigured", { enumerable: true, get: function () { return githubAdapter_1.isGitHubConfigured; } });
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export interface GitHubUser {
|
|
2
|
-
login: string;
|
|
3
|
-
avatar: string;
|
|
4
|
-
}
|
|
5
|
-
export declare const GITHUB_TOKEN_STORAGE_KEY = "github_access_token";
|
|
6
|
-
export declare const GITHUB_USER_STORAGE_KEY = "github_user";
|
|
7
|
-
export declare const storeGitHubAuth: (token: string, user: GitHubUser) => void;
|
|
8
|
-
export declare const clearGitHubAuth: () => void;
|
|
9
|
-
export declare const getStoredToken: () => string | null;
|
|
10
|
-
export declare const getStoredUser: () => GitHubUser | null;
|
|
11
|
-
export declare const isGitHubConfigured: () => boolean;
|
|
12
|
-
export declare const diagnoseGitHubSetup: () => {
|
|
13
|
-
hasToken: boolean;
|
|
14
|
-
hasUser: boolean;
|
|
15
|
-
hasOwner: boolean;
|
|
16
|
-
hasRepo: boolean;
|
|
17
|
-
isComplete: boolean;
|
|
18
|
-
};
|
|
19
|
-
export interface GitHubResult<T = any> {
|
|
20
|
-
success: boolean;
|
|
21
|
-
data?: T;
|
|
22
|
-
error?: string;
|
|
23
|
-
}
|
|
24
|
-
export declare const githubAdapter: {
|
|
25
|
-
createIssue(params: {
|
|
26
|
-
title: string;
|
|
27
|
-
body: string;
|
|
28
|
-
route: string;
|
|
29
|
-
xPercent: number;
|
|
30
|
-
yPercent: number;
|
|
31
|
-
version?: string;
|
|
32
|
-
}): Promise<GitHubResult<{
|
|
33
|
-
number: number;
|
|
34
|
-
html_url: string;
|
|
35
|
-
}>>;
|
|
36
|
-
createComment(issueNumber: number, body: string): Promise<GitHubResult>;
|
|
37
|
-
fetchIssuesForRoute(route: string): Promise<GitHubResult<any[]>>;
|
|
38
|
-
fetchIssuesForRouteAndVersion(route: string, version?: string): Promise<GitHubResult<any[]>>;
|
|
39
|
-
fetchIssueComments(issueNumber: number): Promise<GitHubResult<any[]>>;
|
|
40
|
-
updateComment(commentId: number, body: string): Promise<GitHubResult>;
|
|
41
|
-
deleteComment(commentId: number): Promise<GitHubResult>;
|
|
42
|
-
closeIssue(issueNumber: number): Promise<GitHubResult>;
|
|
43
|
-
reopenIssue(issueNumber: number): Promise<GitHubResult>;
|
|
44
|
-
getRepoFile(path: string): Promise<GitHubResult<{
|
|
45
|
-
text: string;
|
|
46
|
-
sha: string;
|
|
47
|
-
} | null>>;
|
|
48
|
-
putRepoFile(params: {
|
|
49
|
-
path: string;
|
|
50
|
-
text: string;
|
|
51
|
-
message: string;
|
|
52
|
-
sha?: string;
|
|
53
|
-
}): Promise<GitHubResult<{
|
|
54
|
-
sha: string;
|
|
55
|
-
}>>;
|
|
56
|
-
};
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.githubAdapter = exports.diagnoseGitHubSetup = exports.isGitHubConfigured = exports.getStoredUser = exports.getStoredToken = exports.clearGitHubAuth = exports.storeGitHubAuth = exports.GITHUB_USER_STORAGE_KEY = exports.GITHUB_TOKEN_STORAGE_KEY = void 0;
|
|
4
|
-
exports.GITHUB_TOKEN_STORAGE_KEY = 'github_access_token';
|
|
5
|
-
exports.GITHUB_USER_STORAGE_KEY = 'github_user';
|
|
6
|
-
const storeGitHubAuth = (token, user) => {
|
|
7
|
-
localStorage.setItem(exports.GITHUB_TOKEN_STORAGE_KEY, token);
|
|
8
|
-
localStorage.setItem(exports.GITHUB_USER_STORAGE_KEY, JSON.stringify(user));
|
|
9
|
-
};
|
|
10
|
-
exports.storeGitHubAuth = storeGitHubAuth;
|
|
11
|
-
const clearGitHubAuth = () => {
|
|
12
|
-
localStorage.removeItem(exports.GITHUB_TOKEN_STORAGE_KEY);
|
|
13
|
-
localStorage.removeItem(exports.GITHUB_USER_STORAGE_KEY);
|
|
14
|
-
};
|
|
15
|
-
exports.clearGitHubAuth = clearGitHubAuth;
|
|
16
|
-
const getStoredToken = () => {
|
|
17
|
-
return localStorage.getItem(exports.GITHUB_TOKEN_STORAGE_KEY);
|
|
18
|
-
};
|
|
19
|
-
exports.getStoredToken = getStoredToken;
|
|
20
|
-
const getStoredUser = () => {
|
|
21
|
-
const raw = localStorage.getItem(exports.GITHUB_USER_STORAGE_KEY);
|
|
22
|
-
if (!raw)
|
|
23
|
-
return null;
|
|
24
|
-
try {
|
|
25
|
-
return JSON.parse(raw);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
exports.getStoredUser = getStoredUser;
|
|
32
|
-
const isGitHubConfigured = () => {
|
|
33
|
-
return Boolean((0, exports.getStoredToken)() && process.env.VITE_GITHUB_OWNER && process.env.VITE_GITHUB_REPO);
|
|
34
|
-
};
|
|
35
|
-
exports.isGitHubConfigured = isGitHubConfigured;
|
|
36
|
-
const diagnoseGitHubSetup = () => {
|
|
37
|
-
const token = (0, exports.getStoredToken)();
|
|
38
|
-
const user = (0, exports.getStoredUser)();
|
|
39
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
40
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
41
|
-
console.log('🔍 GitHub Configuration Diagnostic:');
|
|
42
|
-
console.log(' Token:', token ? `Present (${token.substring(0, 10)}...)` : 'Missing ❌');
|
|
43
|
-
console.log(' User:', user ? `${user.login}` : 'Not logged in ❌');
|
|
44
|
-
console.log(' Owner:', owner || 'Missing ❌');
|
|
45
|
-
console.log(' Repo:', repo || 'Missing ❌');
|
|
46
|
-
console.log(' Full repo path:', owner && repo ? `${owner}/${repo}` : 'Incomplete ❌');
|
|
47
|
-
console.log('\n💡 To fix 403 Forbidden error:');
|
|
48
|
-
console.log(' 1. Make sure you have write access to the repository');
|
|
49
|
-
console.log(' 2. Check that issues are enabled on the repository');
|
|
50
|
-
console.log(' 3. Re-authenticate to get a fresh token with correct scopes');
|
|
51
|
-
console.log(' 4. Token needs "repo" scope for private repos or "public_repo" for public repos');
|
|
52
|
-
return {
|
|
53
|
-
hasToken: !!token,
|
|
54
|
-
hasUser: !!user,
|
|
55
|
-
hasOwner: !!owner,
|
|
56
|
-
hasRepo: !!repo,
|
|
57
|
-
isComplete: !!(token && user && owner && repo)
|
|
58
|
-
};
|
|
59
|
-
};
|
|
60
|
-
exports.diagnoseGitHubSetup = diagnoseGitHubSetup;
|
|
61
|
-
async function githubProxyRequest(method, endpoint, data) {
|
|
62
|
-
const token = (0, exports.getStoredToken)();
|
|
63
|
-
if (!token) {
|
|
64
|
-
throw new Error('Not authenticated with GitHub');
|
|
65
|
-
}
|
|
66
|
-
console.log(`🔵 GitHub API Request:`, { method, endpoint, hasData: !!data });
|
|
67
|
-
const resp = await fetch('/api/github-api', {
|
|
68
|
-
method: 'POST',
|
|
69
|
-
headers: { 'Content-Type': 'application/json' },
|
|
70
|
-
body: JSON.stringify({ token, method, endpoint, data }),
|
|
71
|
-
});
|
|
72
|
-
const payload = await resp.json();
|
|
73
|
-
console.log(`🔵 GitHub API Response:`, {
|
|
74
|
-
status: resp.status,
|
|
75
|
-
ok: resp.ok,
|
|
76
|
-
payload
|
|
77
|
-
});
|
|
78
|
-
if (!resp.ok) {
|
|
79
|
-
const message = (payload && (payload.message || payload.error)) || `GitHub API error (${resp.status})`;
|
|
80
|
-
if (resp.status === 403) {
|
|
81
|
-
console.error(`❌ 403 Forbidden - Possible causes:
|
|
82
|
-
1. Token doesn't have 'repo' or 'public_repo' scope
|
|
83
|
-
2. You don't have write access to the repository
|
|
84
|
-
3. Issues are disabled on the repository
|
|
85
|
-
4. Token has expired or been revoked
|
|
86
|
-
|
|
87
|
-
Current config:
|
|
88
|
-
- Owner: ${process.env.VITE_GITHUB_OWNER}
|
|
89
|
-
- Repo: ${process.env.VITE_GITHUB_REPO}
|
|
90
|
-
- Endpoint: ${endpoint}
|
|
91
|
-
`);
|
|
92
|
-
}
|
|
93
|
-
throw new Error(message);
|
|
94
|
-
}
|
|
95
|
-
return payload;
|
|
96
|
-
}
|
|
97
|
-
const encodePath = (path) => {
|
|
98
|
-
return path
|
|
99
|
-
.split('/')
|
|
100
|
-
.map((seg) => encodeURIComponent(seg))
|
|
101
|
-
.join('/');
|
|
102
|
-
};
|
|
103
|
-
const base64EncodeUtf8 = (input) => {
|
|
104
|
-
// btoa expects latin1; convert safely for utf-8
|
|
105
|
-
return btoa(unescape(encodeURIComponent(input)));
|
|
106
|
-
};
|
|
107
|
-
const base64DecodeUtf8 = (input) => {
|
|
108
|
-
return decodeURIComponent(escape(atob(input)));
|
|
109
|
-
};
|
|
110
|
-
const getLabelNames = (issue) => {
|
|
111
|
-
const labels = issue?.labels;
|
|
112
|
-
if (!Array.isArray(labels))
|
|
113
|
-
return [];
|
|
114
|
-
return labels
|
|
115
|
-
.map((l) => (typeof l === 'string' ? l : l?.name))
|
|
116
|
-
.filter((n) => typeof n === 'string');
|
|
117
|
-
};
|
|
118
|
-
const issueHasAnyVersion = (issue) => {
|
|
119
|
-
const labelNames = getLabelNames(issue);
|
|
120
|
-
if (labelNames.some((n) => n.startsWith('version:')))
|
|
121
|
-
return true;
|
|
122
|
-
const body = issue?.body || '';
|
|
123
|
-
return body.includes('Version:');
|
|
124
|
-
};
|
|
125
|
-
exports.githubAdapter = {
|
|
126
|
-
async createIssue(params) {
|
|
127
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
128
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
129
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
130
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
131
|
-
try {
|
|
132
|
-
const metadata = [
|
|
133
|
-
`- Route: \`${params.route}\``,
|
|
134
|
-
params.version ? `- Version: \`${params.version}\`` : null,
|
|
135
|
-
`- Coordinates: \`(${params.xPercent.toFixed(1)}%, ${params.yPercent.toFixed(1)}%)\``,
|
|
136
|
-
]
|
|
137
|
-
.filter(Boolean)
|
|
138
|
-
.join('\n');
|
|
139
|
-
const issueBody = {
|
|
140
|
-
title: params.title,
|
|
141
|
-
body: `${params.body}\n\n---\n**Metadata:**\n${metadata}`,
|
|
142
|
-
};
|
|
143
|
-
const data = await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues`, issueBody);
|
|
144
|
-
// Add helpful labels (non-fatal if it fails)
|
|
145
|
-
try {
|
|
146
|
-
const labels = [
|
|
147
|
-
'hale-comment',
|
|
148
|
-
`route:${params.route}`,
|
|
149
|
-
`coords:${Math.round(params.xPercent)},${Math.round(params.yPercent)}`,
|
|
150
|
-
];
|
|
151
|
-
if (params.version)
|
|
152
|
-
labels.push(`version:${params.version}`);
|
|
153
|
-
await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues/${data.number}/labels`, { labels });
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
// ignore label failures
|
|
157
|
-
}
|
|
158
|
-
return { success: true, data };
|
|
159
|
-
}
|
|
160
|
-
catch (e) {
|
|
161
|
-
return { success: false, error: e?.message || 'Failed to create issue' };
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
async createComment(issueNumber, body) {
|
|
165
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
166
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
167
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
168
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
169
|
-
try {
|
|
170
|
-
const data = await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body });
|
|
171
|
-
return { success: true, data };
|
|
172
|
-
}
|
|
173
|
-
catch (e) {
|
|
174
|
-
return { success: false, error: e?.message || 'Failed to create comment' };
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
async fetchIssuesForRoute(route) {
|
|
178
|
-
return exports.githubAdapter.fetchIssuesForRouteAndVersion(route);
|
|
179
|
-
},
|
|
180
|
-
async fetchIssuesForRouteAndVersion(route, version) {
|
|
181
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
182
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
183
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
184
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
185
|
-
try {
|
|
186
|
-
const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/issues?state=all&per_page=100`);
|
|
187
|
-
// Filter by metadata OR labels (route:${route}), and optionally by version
|
|
188
|
-
const filtered = (Array.isArray(data) ? data : [])
|
|
189
|
-
.filter((issue) => {
|
|
190
|
-
const body = issue?.body || '';
|
|
191
|
-
const labels = getLabelNames(issue);
|
|
192
|
-
const bodyMatch = body.includes(`Route: \`${route}\``);
|
|
193
|
-
const labelMatch = labels.includes(`route:${route}`);
|
|
194
|
-
return bodyMatch || labelMatch;
|
|
195
|
-
})
|
|
196
|
-
.filter((issue) => {
|
|
197
|
-
if (!version)
|
|
198
|
-
return true;
|
|
199
|
-
const labels = getLabelNames(issue);
|
|
200
|
-
const body = issue?.body || '';
|
|
201
|
-
const versionLabelMatch = labels.includes(`version:${version}`);
|
|
202
|
-
const bodyVersionMatch = body.includes(`Version: \`${version}\``);
|
|
203
|
-
// Back-compat: if an issue has no version metadata at all, treat it as default "1"
|
|
204
|
-
if (!issueHasAnyVersion(issue) && version === '1')
|
|
205
|
-
return true;
|
|
206
|
-
return versionLabelMatch || bodyVersionMatch;
|
|
207
|
-
});
|
|
208
|
-
return { success: true, data: filtered };
|
|
209
|
-
}
|
|
210
|
-
catch (e) {
|
|
211
|
-
return { success: false, error: e?.message || 'Failed to fetch issues' };
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
async fetchIssueComments(issueNumber) {
|
|
215
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
216
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
217
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
218
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
219
|
-
try {
|
|
220
|
-
const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/issues/${issueNumber}/comments?per_page=100`);
|
|
221
|
-
return { success: true, data };
|
|
222
|
-
}
|
|
223
|
-
catch (e) {
|
|
224
|
-
return { success: false, error: e?.message || 'Failed to fetch issue comments' };
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
async updateComment(commentId, body) {
|
|
228
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
229
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
230
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
231
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
232
|
-
try {
|
|
233
|
-
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/comments/${commentId}`, { body });
|
|
234
|
-
return { success: true, data };
|
|
235
|
-
}
|
|
236
|
-
catch (e) {
|
|
237
|
-
return { success: false, error: e?.message || 'Failed to update comment' };
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
async deleteComment(commentId) {
|
|
241
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
242
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
243
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
244
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
245
|
-
try {
|
|
246
|
-
await githubProxyRequest('DELETE', `/repos/${owner}/${repo}/issues/comments/${commentId}`);
|
|
247
|
-
return { success: true, data: {} };
|
|
248
|
-
}
|
|
249
|
-
catch (e) {
|
|
250
|
-
return { success: false, error: e?.message || 'Failed to delete comment' };
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
async closeIssue(issueNumber) {
|
|
254
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
255
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
256
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
257
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
258
|
-
try {
|
|
259
|
-
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'closed' });
|
|
260
|
-
return { success: true, data };
|
|
261
|
-
}
|
|
262
|
-
catch (e) {
|
|
263
|
-
return { success: false, error: e?.message || 'Failed to close issue' };
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
async reopenIssue(issueNumber) {
|
|
267
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
268
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
269
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
270
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
271
|
-
try {
|
|
272
|
-
const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'open' });
|
|
273
|
-
return { success: true, data };
|
|
274
|
-
}
|
|
275
|
-
catch (e) {
|
|
276
|
-
return { success: false, error: e?.message || 'Failed to reopen issue' };
|
|
277
|
-
}
|
|
278
|
-
},
|
|
279
|
-
async getRepoFile(path) {
|
|
280
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
281
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
282
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
283
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
284
|
-
try {
|
|
285
|
-
const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/contents/${encodePath(path)}`);
|
|
286
|
-
const content = typeof data?.content === 'string' ? data.content.replace(/\n/g, '') : '';
|
|
287
|
-
const sha = data?.sha;
|
|
288
|
-
if (!content || !sha)
|
|
289
|
-
return { success: true, data: null };
|
|
290
|
-
const text = base64DecodeUtf8(content);
|
|
291
|
-
return { success: true, data: { text, sha } };
|
|
292
|
-
}
|
|
293
|
-
catch (e) {
|
|
294
|
-
// If file doesn't exist yet, treat as empty
|
|
295
|
-
if (String(e?.message || '').toLowerCase().includes('not found')) {
|
|
296
|
-
return { success: true, data: null };
|
|
297
|
-
}
|
|
298
|
-
return { success: false, error: e?.message || 'Failed to read repo file' };
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
async putRepoFile(params) {
|
|
302
|
-
if (!(0, exports.isGitHubConfigured)())
|
|
303
|
-
return { success: false, error: 'Please sign in with GitHub' };
|
|
304
|
-
const owner = process.env.VITE_GITHUB_OWNER;
|
|
305
|
-
const repo = process.env.VITE_GITHUB_REPO;
|
|
306
|
-
try {
|
|
307
|
-
const payload = {
|
|
308
|
-
message: params.message,
|
|
309
|
-
content: base64EncodeUtf8(params.text),
|
|
310
|
-
};
|
|
311
|
-
if (params.sha)
|
|
312
|
-
payload.sha = params.sha;
|
|
313
|
-
const data = await githubProxyRequest('PUT', `/repos/${owner}/${repo}/contents/${encodePath(params.path)}`, payload);
|
|
314
|
-
const newSha = data?.content?.sha;
|
|
315
|
-
return { success: true, data: { sha: newSha || params.sha || '' } };
|
|
316
|
-
}
|
|
317
|
-
catch (e) {
|
|
318
|
-
return { success: false, error: e?.message || 'Failed to write repo file' };
|
|
319
|
-
}
|
|
320
|
-
},
|
|
321
|
-
};
|
package/dist/types/index.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export interface Comment {
|
|
2
|
-
id: string;
|
|
3
|
-
author?: string;
|
|
4
|
-
text: string;
|
|
5
|
-
createdAt: string;
|
|
6
|
-
githubCommentId?: number;
|
|
7
|
-
parentCommentId?: string;
|
|
8
|
-
parentGitHubCommentId?: number;
|
|
9
|
-
}
|
|
10
|
-
export type SyncStatus = 'synced' | 'local' | 'pending' | 'syncing' | 'error';
|
|
11
|
-
export type ThreadStatus = 'open' | 'closed';
|
|
12
|
-
export interface Thread {
|
|
13
|
-
id: string;
|
|
14
|
-
xPercent: number;
|
|
15
|
-
yPercent: number;
|
|
16
|
-
route: string;
|
|
17
|
-
version?: string;
|
|
18
|
-
comments: Comment[];
|
|
19
|
-
issueNumber?: number;
|
|
20
|
-
issueUrl?: string;
|
|
21
|
-
provider?: 'github';
|
|
22
|
-
syncStatus?: SyncStatus;
|
|
23
|
-
syncError?: string;
|
|
24
|
-
status?: ThreadStatus;
|
|
25
|
-
}
|
package/dist/types/index.js
DELETED
package/dist/utils/version.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const getVersionFromPathOrQuery: (pathname: string, search: string) => string | undefined;
|
package/dist/utils/version.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getVersionFromPathOrQuery = void 0;
|
|
4
|
-
const getVersionFromPathOrQuery = (pathname, search) => {
|
|
5
|
-
try {
|
|
6
|
-
const params = new URLSearchParams(search || '');
|
|
7
|
-
const fromQuery = params.get('version') || params.get('v');
|
|
8
|
-
if (fromQuery && String(fromQuery).trim())
|
|
9
|
-
return String(fromQuery).trim();
|
|
10
|
-
// Common pattern: /v3/... or /version/3/...
|
|
11
|
-
const m1 = pathname.match(/^\/v(\d+)(?:\/|$)/i);
|
|
12
|
-
if (m1?.[1])
|
|
13
|
-
return m1[1];
|
|
14
|
-
const m2 = pathname.match(/\/version\/(\d+)(?:\/|$)/i);
|
|
15
|
-
if (m2?.[1])
|
|
16
|
-
return m2[1];
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
// ignore
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
};
|
|
23
|
-
exports.getVersionFromPathOrQuery = getVersionFromPathOrQuery;
|