farseer-cli 1.0.0
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/LICENSE +15 -0
- package/README.md +741 -0
- package/dist/commands/app.d.ts +2 -0
- package/dist/commands/app.js +349 -0
- package/dist/commands/app.js.map +7 -0
- package/dist/commands/apps.d.ts +2 -0
- package/dist/commands/apps.js +111 -0
- package/dist/commands/apps.js.map +7 -0
- package/dist/commands/checkout.d.ts +2 -0
- package/dist/commands/checkout.js +166 -0
- package/dist/commands/checkout.js.map +7 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +139 -0
- package/dist/commands/config.js.map +7 -0
- package/dist/commands/diff.d.ts +2 -0
- package/dist/commands/diff.js +183 -0
- package/dist/commands/diff.js.map +7 -0
- package/dist/commands/files.js +99 -0
- package/dist/commands/files.js.map +7 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +79 -0
- package/dist/commands/install.js.map +7 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +92 -0
- package/dist/commands/list.js.map +7 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +134 -0
- package/dist/commands/login.js.map +7 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +59 -0
- package/dist/commands/logout.js.map +7 -0
- package/dist/commands/mcp-server.d.ts +8 -0
- package/dist/commands/mcp-server.js +41 -0
- package/dist/commands/mcp-server.js.map +7 -0
- package/dist/commands/model.d.ts +2 -0
- package/dist/commands/model.js +189 -0
- package/dist/commands/model.js.map +7 -0
- package/dist/commands/pull.d.ts +2 -0
- package/dist/commands/pull.js +287 -0
- package/dist/commands/pull.js.map +7 -0
- package/dist/commands/push.d.ts +2 -0
- package/dist/commands/push.js +251 -0
- package/dist/commands/push.js.map +7 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +246 -0
- package/dist/commands/run.js.map +7 -0
- package/dist/commands/setup.d.ts +2 -0
- package/dist/commands/setup.js +137 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +145 -0
- package/dist/commands/status.js.map +7 -0
- package/dist/commands/unsetup.d.ts +2 -0
- package/dist/commands/unsetup.js +122 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +63 -0
- package/dist/commands/whoami.js.map +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +135 -0
- package/dist/index.js.map +7 -0
- package/dist/mcp/index.d.ts +7 -0
- package/dist/mcp/index.js +35 -0
- package/dist/mcp/index.js.map +7 -0
- package/dist/mcp/prompts/workflows.d.ts +7 -0
- package/dist/mcp/prompts/workflows.js +374 -0
- package/dist/mcp/prompts/workflows.js.map +7 -0
- package/dist/mcp/resources/documentation.d.ts +8 -0
- package/dist/mcp/resources/documentation.js +167 -0
- package/dist/mcp/resources/documentation.js.map +7 -0
- package/dist/mcp/server.d.ts +7 -0
- package/dist/mcp/server.js +49 -0
- package/dist/mcp/server.js.map +7 -0
- package/dist/mcp/tools/appTools.d.ts +7 -0
- package/dist/mcp/tools/appTools.js +377 -0
- package/dist/mcp/tools/appTools.js.map +7 -0
- package/dist/mcp/tools/authTools.d.ts +7 -0
- package/dist/mcp/tools/authTools.js +158 -0
- package/dist/mcp/tools/authTools.js.map +7 -0
- package/dist/mcp/tools/modelTools.d.ts +7 -0
- package/dist/mcp/tools/modelTools.js +331 -0
- package/dist/mcp/tools/modelTools.js.map +7 -0
- package/dist/mcp/tools/runTools.d.ts +7 -0
- package/dist/mcp/tools/runTools.js +231 -0
- package/dist/mcp/tools/runTools.js.map +7 -0
- package/dist/mcp/tools/syncTools.d.ts +7 -0
- package/dist/mcp/tools/syncTools.js +382 -0
- package/dist/mcp/tools/syncTools.js.map +7 -0
- package/dist/mcp/utils/helpers.d.ts +69 -0
- package/dist/mcp/utils/helpers.js +113 -0
- package/dist/mcp/utils/helpers.js.map +7 -0
- package/dist/services/appSyncService.d.ts +75 -0
- package/dist/services/appSyncService.js +370 -0
- package/dist/services/appSyncService.js.map +7 -0
- package/dist/services/configService.d.ts +39 -0
- package/dist/services/configService.js +196 -0
- package/dist/services/configService.js.map +7 -0
- package/dist/services/farseerApi.d.ts +166 -0
- package/dist/services/farseerApi.js +378 -0
- package/dist/services/farseerApi.js.map +7 -0
- package/dist/services/farseerFactory.d.ts +88 -0
- package/dist/services/farseerFactory.js +179 -0
- package/dist/services/farseerFactory.js.map +7 -0
- package/dist/services/farseerService.d.ts +96 -0
- package/dist/services/farseerService.js +614 -0
- package/dist/services/farseerService.js.map +7 -0
- package/dist/services/gitService.d.ts +31 -0
- package/dist/services/gitService.js +134 -0
- package/dist/services/gitService.js.map +7 -0
- package/dist/services/syncService.d.ts +44 -0
- package/dist/services/syncService.js +320 -0
- package/dist/services/syncService.js.map +7 -0
- package/dist/utils/constants.d.ts +7 -0
- package/dist/utils/constants.js +46 -0
- package/dist/utils/constants.js.map +7 -0
- package/dist/utils/helpers.d.ts +69 -0
- package/dist/utils/helpers.js +413 -0
- package/dist/utils/helpers.js.map +7 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.js +76 -0
- package/dist/utils/logger.js.map +7 -0
- package/package.json +62 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/services/syncService.ts"],
|
|
4
|
+
"sourcesContent": ["import * as fs from 'fs';\nimport * as path from 'path';\nimport { IFarseerClient, RemoteFile, DEFAULT_SCRIPT_EXTENSIONS } from './farseerFactory';\nimport { calculateHash, getTenantFilesDir, getSyncFilePath, ensureDirectoryExists, getAllFilesInDir } from '../utils/helpers';\n\nexport interface SyncFileInfo {\n localHash: string;\n remoteHash: string;\n metadata?: {\n uploadTime?: string;\n uploaderEmail?: string;\n uploaderName?: string;\n lastFetched?: string;\n };\n}\n\nexport interface SyncState {\n lastSync: string;\n files: Record<string, SyncFileInfo>;\n}\n\nexport interface SyncStatus {\n modifiedLocally: string[];\n modifiedRemotely: string[];\n onlyLocal: string[];\n onlyRemote: string[];\n inSync: string[];\n}\n\nexport class SyncService {\n private tenant: string;\n private farseerClient: IFarseerClient;\n\n constructor(tenant: string, farseerClient: IFarseerClient) {\n this.tenant = tenant;\n this.farseerClient = farseerClient;\n }\n\n loadSyncState(): SyncState {\n const syncFilePath = getSyncFilePath(this.tenant);\n\n if (!fs.existsSync(syncFilePath)) {\n return {\n lastSync: '',\n files: {},\n };\n }\n\n try {\n const content = fs.readFileSync(syncFilePath, 'utf-8');\n return JSON.parse(content) as SyncState;\n } catch {\n return {\n lastSync: '',\n files: {},\n };\n }\n }\n\n saveSyncState(state: SyncState): void {\n const syncFilePath = getSyncFilePath(this.tenant);\n ensureDirectoryExists(path.dirname(syncFilePath));\n fs.writeFileSync(syncFilePath, JSON.stringify(state, null, 2), 'utf-8');\n }\n\n async getStatus(options?: { all?: boolean }): Promise<SyncStatus> {\n const syncState = this.loadSyncState();\n const filesDir = getTenantFilesDir(this.tenant);\n\n // Get local files\n let localFiles = getAllFilesInDir(filesDir);\n\n // Filter to scripts only unless --all is specified\n if (!options?.all) {\n localFiles = localFiles.filter(f =>\n DEFAULT_SCRIPT_EXTENSIONS.some(ext => f.toLowerCase().endsWith(ext))\n );\n }\n\n const localFileHashes: Record<string, string> = {};\n\n for (const file of localFiles) {\n const fullPath = path.join(filesDir, file);\n const content = fs.readFileSync(fullPath);\n localFileHashes[file] = calculateHash(content);\n }\n\n // Get remote files\n let remoteFiles = await this.farseerClient.listFiles();\n\n // Filter to scripts only unless --all is specified\n if (!options?.all) {\n remoteFiles = remoteFiles.filter(f =>\n DEFAULT_SCRIPT_EXTENSIONS.some(ext => f.name.toLowerCase().endsWith(ext))\n );\n }\n\n const remoteFileHashes: Record<string, string> = {};\n\n for (const file of remoteFiles) {\n const content = await this.farseerClient.getFileContentAsBuffer(file.reference);\n remoteFileHashes[file.path] = calculateHash(content);\n }\n\n const status: SyncStatus = {\n modifiedLocally: [],\n modifiedRemotely: [],\n onlyLocal: [],\n onlyRemote: [],\n inSync: [],\n };\n\n const allFiles = new Set([...Object.keys(localFileHashes), ...Object.keys(remoteFileHashes)]);\n\n for (const file of allFiles) {\n const localHash = localFileHashes[file];\n const remoteHash = remoteFileHashes[file];\n const syncInfo = syncState.files[file];\n\n if (localHash && remoteHash) {\n // File exists both locally and remotely\n if (localHash === remoteHash) {\n status.inSync.push(file);\n } else if (syncInfo) {\n // We have sync state to compare\n const localChanged = localHash !== syncInfo.localHash;\n const remoteChanged = remoteHash !== syncInfo.remoteHash;\n\n if (localChanged && remoteChanged) {\n // Both changed - conflict (treat as modified locally for now)\n status.modifiedLocally.push(file);\n status.modifiedRemotely.push(file);\n } else if (localChanged) {\n status.modifiedLocally.push(file);\n } else if (remoteChanged) {\n status.modifiedRemotely.push(file);\n } else {\n status.inSync.push(file);\n }\n } else {\n // No sync state - files are different, treat as conflict\n status.modifiedLocally.push(file);\n }\n } else if (localHash && !remoteHash) {\n // Only exists locally\n if (syncInfo && syncInfo.remoteHash) {\n // Was synced before, deleted on remote\n status.modifiedRemotely.push(file);\n } else {\n status.onlyLocal.push(file);\n }\n } else if (!localHash && remoteHash) {\n // Only exists remotely\n if (syncInfo && syncInfo.localHash) {\n // Was synced before, deleted locally\n status.modifiedLocally.push(file);\n } else {\n status.onlyRemote.push(file);\n }\n }\n }\n\n return status;\n }\n\n async pull(options?: { all?: boolean }): Promise<{\n downloaded: string[];\n deleted: string[];\n unchanged: string[];\n }> {\n const filesDir = getTenantFilesDir(this.tenant);\n ensureDirectoryExists(filesDir);\n\n const syncState = this.loadSyncState();\n let remoteFiles = await this.farseerClient.listFiles();\n\n // Filter to scripts only unless --all is specified\n if (!options?.all) {\n remoteFiles = remoteFiles.filter(f =>\n DEFAULT_SCRIPT_EXTENSIONS.some(ext => f.name.toLowerCase().endsWith(ext))\n );\n }\n\n // Batch fetch metadata for all files\n remoteFiles = await this.fetchMetadataForFiles(remoteFiles);\n\n const result = {\n downloaded: [] as string[],\n deleted: [] as string[],\n unchanged: [] as string[],\n };\n\n const remoteFilePaths = new Set(remoteFiles.map(f => f.path));\n\n // Download/update files from remote\n for (const file of remoteFiles) {\n const localPath = path.join(filesDir, file.path);\n const content = await this.farseerClient.getFileContentAsBuffer(file.reference);\n const remoteHash = calculateHash(content);\n\n let needsUpdate = true;\n\n if (fs.existsSync(localPath)) {\n const localContent = fs.readFileSync(localPath);\n const localHash = calculateHash(localContent);\n\n if (localHash === remoteHash) {\n needsUpdate = false;\n result.unchanged.push(file.path);\n }\n }\n\n if (needsUpdate) {\n ensureDirectoryExists(path.dirname(localPath));\n fs.writeFileSync(localPath, content);\n result.downloaded.push(file.path);\n }\n\n // Update sync state with metadata\n syncState.files[file.path] = {\n localHash: remoteHash,\n remoteHash: remoteHash,\n metadata: file.metadata ? {\n uploadTime: file.metadata.uploadTime,\n uploaderEmail: file.metadata.uploader?.email,\n uploaderName: file.metadata.uploader\n ? `${file.metadata.uploader.firstName} ${file.metadata.uploader.lastName}`.trim()\n : undefined,\n lastFetched: new Date().toISOString(),\n } : undefined,\n };\n }\n\n // Check for files that were deleted on remote\n const localFiles = getAllFilesInDir(filesDir);\n for (const localFile of localFiles) {\n if (!remoteFilePaths.has(localFile)) {\n // File exists locally but not on remote\n const syncInfo = syncState.files[localFile];\n if (syncInfo) {\n // Was synced before, now deleted on remote - delete locally\n const localPath = path.join(filesDir, localFile);\n fs.unlinkSync(localPath);\n result.deleted.push(localFile);\n delete syncState.files[localFile];\n }\n // If no sync info, it's a new local file - don't delete\n }\n }\n\n syncState.lastSync = new Date().toISOString();\n this.saveSyncState(syncState);\n\n return result;\n }\n\n async push(): Promise<{\n uploaded: string[];\n updated: string[];\n deleted: string[];\n unchanged: string[];\n }> {\n const filesDir = getTenantFilesDir(this.tenant);\n const syncState = this.loadSyncState();\n\n const result = {\n uploaded: [] as string[],\n updated: [] as string[],\n deleted: [] as string[],\n unchanged: [] as string[],\n };\n\n // Get current remote files\n const remoteFiles = await this.farseerClient.listFiles();\n const remoteFileMap = new Map<string, RemoteFile>();\n for (const file of remoteFiles) {\n remoteFileMap.set(file.path, file);\n }\n\n // Get local files\n const localFiles = getAllFilesInDir(filesDir);\n\n // Upload/update local files\n for (const localFile of localFiles) {\n const localPath = path.join(filesDir, localFile);\n const content = fs.readFileSync(localPath);\n const localHash = calculateHash(content);\n\n const remoteFile = remoteFileMap.get(localFile);\n\n if (remoteFile) {\n // File exists on remote - check if update needed\n const remoteContent = await this.farseerClient.getFileContentAsBuffer(remoteFile.reference);\n const remoteHash = calculateHash(remoteContent);\n\n if (localHash !== remoteHash) {\n await this.farseerClient.updateFile(remoteFile.reference, content, path.basename(localFile));\n result.updated.push(localFile);\n } else {\n result.unchanged.push(localFile);\n }\n } else {\n // File doesn't exist on remote - create it\n const pathParts = localFile.split('/');\n const fileName = pathParts.pop()!;\n const folderPath = ['Files', ...pathParts];\n\n await this.farseerClient.createFile(content, fileName, folderPath);\n result.uploaded.push(localFile);\n }\n\n // Update sync state\n syncState.files[localFile] = {\n localHash: localHash,\n remoteHash: localHash,\n };\n }\n\n // Delete files on remote that were deleted locally\n const localFileSet = new Set(localFiles);\n for (const [remotePath, remoteFile] of remoteFileMap) {\n if (!localFileSet.has(remotePath)) {\n const syncInfo = syncState.files[remotePath];\n if (syncInfo) {\n // Was synced before, now deleted locally - delete on remote\n await this.farseerClient.deleteFile(remoteFile.reference);\n result.deleted.push(remotePath);\n delete syncState.files[remotePath];\n }\n }\n }\n\n syncState.lastSync = new Date().toISOString();\n this.saveSyncState(syncState);\n\n return result;\n }\n\n async checkRemoteChanges(): Promise<boolean> {\n const syncState = this.loadSyncState();\n let remoteFiles = await this.farseerClient.listFiles();\n\n // Filter to scripts only (same as pull/status) to avoid false positives\n // from non-script files like .json, .png, etc.\n remoteFiles = remoteFiles.filter(f =>\n DEFAULT_SCRIPT_EXTENSIONS.some(ext => f.name.toLowerCase().endsWith(ext))\n );\n\n for (const file of remoteFiles) {\n const content = await this.farseerClient.getFileContentAsBuffer(file.reference);\n const remoteHash = calculateHash(content);\n const syncInfo = syncState.files[file.path];\n\n if (!syncInfo || syncInfo.remoteHash !== remoteHash) {\n return true; // Remote has changes\n }\n }\n\n // Check for deleted files on remote (only for script files in sync state)\n for (const filePath of Object.keys(syncState.files)) {\n // Only check script files\n const isScript = DEFAULT_SCRIPT_EXTENSIONS.some(ext => filePath.toLowerCase().endsWith(ext));\n if (!isScript) continue;\n\n const exists = remoteFiles.some(f => f.path === filePath);\n if (!exists && syncState.files[filePath].remoteHash) {\n return true; // File was deleted on remote\n }\n }\n\n return false;\n }\n\n async getFileDiff(filePath: string): Promise<{\n localContent: string | null;\n remoteContent: string | null;\n }> {\n const filesDir = getTenantFilesDir(this.tenant);\n const localPath = path.join(filesDir, filePath);\n\n let localContent: string | null = null;\n let remoteContent: string | null = null;\n\n if (fs.existsSync(localPath)) {\n // For diff, read as text (diff only makes sense for text files)\n localContent = fs.readFileSync(localPath, 'utf-8');\n }\n\n const remoteFile = await this.farseerClient.getFileByPath(filePath);\n if (remoteFile) {\n remoteContent = await this.farseerClient.getFileContent(remoteFile.reference);\n }\n\n return { localContent, remoteContent };\n }\n\n /**\n * Batch fetch metadata for multiple files in parallel.\n * Fetches metadata in batches of 10 to avoid overwhelming the API.\n * Non-critical operation - failures are silently ignored.\n */\n private async fetchMetadataForFiles(files: RemoteFile[]): Promise<RemoteFile[]> {\n const batchSize = 10;\n\n for (let i = 0; i < files.length; i += batchSize) {\n const batch = files.slice(i, i + batchSize);\n\n await Promise.all(batch.map(async (file) => {\n try {\n const metadata = await this.farseerClient.getFileMetadata(file.reference);\n if (metadata) {\n file.metadata = metadata;\n }\n } catch {\n // Silently ignore metadata fetch errors - non-critical\n }\n }));\n }\n\n return files;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const FARSEER_CLIENT_URL = "https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client/release-1.4.5.tar";
|
|
2
|
+
export declare const FARSEER_CLIENT_AXIOS_URL = "https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client-axios/6898c0cb-5dca-4b2f-b325-119efc7f099e/v1.0.1.tar";
|
|
3
|
+
export declare const KEYCLOAK_TOKEN_URL = "https://login.farseer.io/auth/realms/master/protocol/openid-connect/token";
|
|
4
|
+
export declare const KEYCLOAK_CLIENT_ID = "security-admin-console";
|
|
5
|
+
export declare const SCRIPTS_FOLDER_PATH: string[];
|
|
6
|
+
export declare const SCRIPT_EXTENSIONS: string[];
|
|
7
|
+
export declare const CLI_GIT_AUTHOR = "Farseer CLI <cli@farseer.io>";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var constants_exports = {};
|
|
19
|
+
__export(constants_exports, {
|
|
20
|
+
CLI_GIT_AUTHOR: () => CLI_GIT_AUTHOR,
|
|
21
|
+
FARSEER_CLIENT_AXIOS_URL: () => FARSEER_CLIENT_AXIOS_URL,
|
|
22
|
+
FARSEER_CLIENT_URL: () => FARSEER_CLIENT_URL,
|
|
23
|
+
KEYCLOAK_CLIENT_ID: () => KEYCLOAK_CLIENT_ID,
|
|
24
|
+
KEYCLOAK_TOKEN_URL: () => KEYCLOAK_TOKEN_URL,
|
|
25
|
+
SCRIPTS_FOLDER_PATH: () => SCRIPTS_FOLDER_PATH,
|
|
26
|
+
SCRIPT_EXTENSIONS: () => SCRIPT_EXTENSIONS
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(constants_exports);
|
|
29
|
+
const FARSEER_CLIENT_URL = "https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client/release-1.4.5.tar";
|
|
30
|
+
const FARSEER_CLIENT_AXIOS_URL = "https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client-axios/6898c0cb-5dca-4b2f-b325-119efc7f099e/v1.0.1.tar";
|
|
31
|
+
const KEYCLOAK_TOKEN_URL = "https://login.farseer.io/auth/realms/master/protocol/openid-connect/token";
|
|
32
|
+
const KEYCLOAK_CLIENT_ID = "security-admin-console";
|
|
33
|
+
const SCRIPTS_FOLDER_PATH = ["Files", "Scripts"];
|
|
34
|
+
const SCRIPT_EXTENSIONS = [".ts", ".js", ".mjs", ".cjs"];
|
|
35
|
+
const CLI_GIT_AUTHOR = "Farseer CLI <cli@farseer.io>";
|
|
36
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
37
|
+
0 && (module.exports = {
|
|
38
|
+
CLI_GIT_AUTHOR,
|
|
39
|
+
FARSEER_CLIENT_AXIOS_URL,
|
|
40
|
+
FARSEER_CLIENT_URL,
|
|
41
|
+
KEYCLOAK_CLIENT_ID,
|
|
42
|
+
KEYCLOAK_TOKEN_URL,
|
|
43
|
+
SCRIPTS_FOLDER_PATH,
|
|
44
|
+
SCRIPT_EXTENSIONS
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/utils/constants.ts"],
|
|
4
|
+
"sourcesContent": ["// Farseer client package URLs - update these when new versions are released\nexport const FARSEER_CLIENT_URL = 'https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client/release-1.4.5.tar';\nexport const FARSEER_CLIENT_AXIOS_URL = 'https://storage.googleapis.com/farseer-remote-jobs-results/farseer-client-axios/6898c0cb-5dca-4b2f-b325-119efc7f099e/v1.0.1.tar';\n\n// Keycloak auth configuration\nexport const KEYCLOAK_TOKEN_URL = 'https://login.farseer.io/auth/realms/master/protocol/openid-connect/token';\nexport const KEYCLOAK_CLIENT_ID = 'security-admin-console';\n\n// Default paths\nexport const SCRIPTS_FOLDER_PATH = ['Files', 'Scripts'];\n\n// Supported script file extensions\nexport const SCRIPT_EXTENSIONS = ['.ts', '.js', '.mjs', '.cjs'];\n\n// Git commit author for CLI-generated commits\nexport const CLI_GIT_AUTHOR = 'Farseer CLI <cli@farseer.io>';\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACO,MAAM,qBAAqB;AAC3B,MAAM,2BAA2B;AAGjC,MAAM,qBAAqB;AAC3B,MAAM,qBAAqB;AAG3B,MAAM,sBAAsB,CAAC,SAAS,SAAS;AAG/C,MAAM,oBAAoB,CAAC,OAAO,OAAO,QAAQ,MAAM;AAGvD,MAAM,iBAAiB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare function calculateHash(content: string | Buffer): string;
|
|
2
|
+
export declare function getAppsDir(): string;
|
|
3
|
+
export declare function getTenantDir(tenant: string): string;
|
|
4
|
+
export declare function getTenantFilesDir(tenant: string): string;
|
|
5
|
+
export declare function getTenantSrcDir(tenant: string): string;
|
|
6
|
+
export declare function getSyncFilePath(tenant: string): string;
|
|
7
|
+
export declare function getTenantAppsDir(tenant: string): string;
|
|
8
|
+
export declare function ensureDirectoryExists(dirPath: string): void;
|
|
9
|
+
export declare function getRelativePath(fullPath: string, basePath: string): string;
|
|
10
|
+
export declare function getAllFiles(dirPath: string, basePath?: string): string[];
|
|
11
|
+
export declare function getAllFilesInDir(dirPath: string, basePath?: string): string[];
|
|
12
|
+
export declare function isScriptFile(filename: string): boolean;
|
|
13
|
+
export declare function isTextFile(filename: string): boolean;
|
|
14
|
+
export declare function formatFileSize(bytes: number): string;
|
|
15
|
+
export declare function formatDate(date: Date | string): string;
|
|
16
|
+
export declare function getCredentialsHint(tenant: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve tenant from argument or checkout.
|
|
19
|
+
* If tenant is provided, use it. Otherwise, use checked-out tenant.
|
|
20
|
+
* Returns null if no tenant is available.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResolvedCheckout {
|
|
23
|
+
organisation: string;
|
|
24
|
+
tenant: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve organisation and tenant from argument or checkout.
|
|
28
|
+
* When only tenant is provided, assumes organisation = tenant.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveOrgAndTenant(tenantArg?: string): ResolvedCheckout | null;
|
|
31
|
+
export declare function resolveTenant(tenantArg?: string): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve tenant or exit with error if not available.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveTenantOrExit(tenantArg?: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve organisation and tenant or exit with error.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveOrgAndTenantOrExit(tenantArg?: string): ResolvedCheckout;
|
|
40
|
+
/**
|
|
41
|
+
* Check if a string is a known tenant (has credentials configured).
|
|
42
|
+
*/
|
|
43
|
+
export declare function isKnownTenant(name: string): boolean;
|
|
44
|
+
export interface ParsedAppArgs {
|
|
45
|
+
organisation: string;
|
|
46
|
+
tenant: string;
|
|
47
|
+
appName: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse variadic arguments to extract tenant and app name.
|
|
51
|
+
* If first arg is a known tenant, use it as tenant and rest as app name.
|
|
52
|
+
* Otherwise, use checked-out tenant and all args as app name.
|
|
53
|
+
*
|
|
54
|
+
* @param args Array of arguments (from variadic command)
|
|
55
|
+
* @returns { organisation: string, tenant: string, appName: string }
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseAppArgs(args: string[]): ParsedAppArgs;
|
|
58
|
+
interface CredentialConfig {
|
|
59
|
+
basePath: string;
|
|
60
|
+
tenantId: string;
|
|
61
|
+
apiKey: string;
|
|
62
|
+
}
|
|
63
|
+
export declare function injectCredentials(code: string, credential: CredentialConfig): string;
|
|
64
|
+
export declare function stripCredentials(code: string): string;
|
|
65
|
+
export declare function hasInjectedCredentials(code: string): boolean;
|
|
66
|
+
export declare function hasEmptyFarseerClient(code: string): boolean;
|
|
67
|
+
export declare function injectCredentialsInDir(srcDir: string, credential: CredentialConfig): number;
|
|
68
|
+
export declare function stripCredentialsInDir(srcDir: string): number;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var helpers_exports = {};
|
|
29
|
+
__export(helpers_exports, {
|
|
30
|
+
appendToAuditLog: () => appendToAuditLog,
|
|
31
|
+
calculateHash: () => calculateHash,
|
|
32
|
+
ensureDirectoryExists: () => ensureDirectoryExists,
|
|
33
|
+
formatDate: () => formatDate,
|
|
34
|
+
formatFileSize: () => formatFileSize,
|
|
35
|
+
getAllFiles: () => getAllFiles,
|
|
36
|
+
getAllFilesInDir: () => getAllFilesInDir,
|
|
37
|
+
getAppsDir: () => getAppsDir,
|
|
38
|
+
getAuditLogPath: () => getAuditLogPath,
|
|
39
|
+
getCredentialsHint: () => getCredentialsHint,
|
|
40
|
+
getRelativePath: () => getRelativePath,
|
|
41
|
+
getSyncFilePath: () => getSyncFilePath,
|
|
42
|
+
getTenantAppsDir: () => getTenantAppsDir,
|
|
43
|
+
getTenantDir: () => getTenantDir,
|
|
44
|
+
getTenantFilesDir: () => getTenantFilesDir,
|
|
45
|
+
getTenantSrcDir: () => getTenantSrcDir,
|
|
46
|
+
hasEmptyFarseerClient: () => hasEmptyFarseerClient,
|
|
47
|
+
hasInjectedCredentials: () => hasInjectedCredentials,
|
|
48
|
+
injectCredentials: () => injectCredentials,
|
|
49
|
+
injectCredentialsInDir: () => injectCredentialsInDir,
|
|
50
|
+
isInRemotejobsRepo: () => isInRemotejobsRepo,
|
|
51
|
+
isKnownTenant: () => isKnownTenant,
|
|
52
|
+
isScriptFile: () => isScriptFile,
|
|
53
|
+
isTextFile: () => isTextFile,
|
|
54
|
+
parseAppArgs: () => parseAppArgs,
|
|
55
|
+
resolveOrgAndTenant: () => resolveOrgAndTenant,
|
|
56
|
+
resolveOrgAndTenantOrExit: () => resolveOrgAndTenantOrExit,
|
|
57
|
+
resolveTenant: () => resolveTenant,
|
|
58
|
+
resolveTenantOrExit: () => resolveTenantOrExit,
|
|
59
|
+
resolveTenantWithOrgMapping: () => resolveTenantWithOrgMapping,
|
|
60
|
+
stripCredentials: () => stripCredentials,
|
|
61
|
+
stripCredentialsInDir: () => stripCredentialsInDir
|
|
62
|
+
});
|
|
63
|
+
module.exports = __toCommonJS(helpers_exports);
|
|
64
|
+
var crypto = __toESM(require("crypto"));
|
|
65
|
+
var path = __toESM(require("path"));
|
|
66
|
+
var fs = __toESM(require("fs"));
|
|
67
|
+
var import_configService = require("../services/configService");
|
|
68
|
+
var import_logger = require("./logger");
|
|
69
|
+
function calculateHash(content) {
|
|
70
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
71
|
+
}
|
|
72
|
+
function getAppsDir() {
|
|
73
|
+
return path.join(process.cwd(), "farseer");
|
|
74
|
+
}
|
|
75
|
+
function getTenantDir(tenant) {
|
|
76
|
+
return path.join(getAppsDir(), tenant);
|
|
77
|
+
}
|
|
78
|
+
function getTenantFilesDir(tenant) {
|
|
79
|
+
return path.join(getTenantDir(tenant), "files");
|
|
80
|
+
}
|
|
81
|
+
function getTenantSrcDir(tenant) {
|
|
82
|
+
return path.join(getTenantFilesDir(tenant), "Scripts");
|
|
83
|
+
}
|
|
84
|
+
function getSyncFilePath(tenant) {
|
|
85
|
+
return path.join(getTenantDir(tenant), ".farseer-sync.json");
|
|
86
|
+
}
|
|
87
|
+
function getAuditLogPath(tenant) {
|
|
88
|
+
return path.join(getTenantDir(tenant), ".farseer-audit.log");
|
|
89
|
+
}
|
|
90
|
+
function getTenantAppsDir(tenant) {
|
|
91
|
+
return path.join(getTenantDir(tenant), "apps");
|
|
92
|
+
}
|
|
93
|
+
function ensureDirectoryExists(dirPath) {
|
|
94
|
+
if (!fs.existsSync(dirPath)) {
|
|
95
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function isInRemotejobsRepo() {
|
|
99
|
+
try {
|
|
100
|
+
const appsDir = getAppsDir();
|
|
101
|
+
const repoRoot = path.dirname(appsDir);
|
|
102
|
+
const hasCli = fs.existsSync(path.join(repoRoot, "cli"));
|
|
103
|
+
const hasDocs = fs.existsSync(path.join(repoRoot, "docs"));
|
|
104
|
+
return hasCli && hasDocs;
|
|
105
|
+
} catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function getRelativePath(fullPath, basePath) {
|
|
110
|
+
return path.relative(basePath, fullPath);
|
|
111
|
+
}
|
|
112
|
+
function getAllFiles(dirPath, basePath) {
|
|
113
|
+
if (!fs.existsSync(dirPath)) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const base = basePath || dirPath;
|
|
117
|
+
const files = [];
|
|
118
|
+
const items = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
119
|
+
for (const item of items) {
|
|
120
|
+
const fullPath = path.join(dirPath, item.name);
|
|
121
|
+
if (item.isDirectory()) {
|
|
122
|
+
files.push(...getAllFiles(fullPath, base));
|
|
123
|
+
} else if (item.isFile() && isScriptFile(item.name)) {
|
|
124
|
+
files.push(getRelativePath(fullPath, base));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return files;
|
|
128
|
+
}
|
|
129
|
+
function getAllFilesInDir(dirPath, basePath) {
|
|
130
|
+
if (!fs.existsSync(dirPath)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
const base = basePath || dirPath;
|
|
134
|
+
const files = [];
|
|
135
|
+
const items = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
136
|
+
for (const item of items) {
|
|
137
|
+
const fullPath = path.join(dirPath, item.name);
|
|
138
|
+
if (item.isDirectory()) {
|
|
139
|
+
files.push(...getAllFilesInDir(fullPath, base));
|
|
140
|
+
} else if (item.isFile()) {
|
|
141
|
+
files.push(getRelativePath(fullPath, base));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return files;
|
|
145
|
+
}
|
|
146
|
+
function isScriptFile(filename) {
|
|
147
|
+
const ext = path.extname(filename).toLowerCase();
|
|
148
|
+
return [".ts", ".js", ".mjs", ".cjs"].includes(ext);
|
|
149
|
+
}
|
|
150
|
+
function isTextFile(filename) {
|
|
151
|
+
const ext = path.extname(filename).toLowerCase().slice(1);
|
|
152
|
+
return ["ts", "js", "mjs", "cjs", "json", "txt", "md", "csv", "xml", "html", "css", "yaml", "yml"].includes(ext);
|
|
153
|
+
}
|
|
154
|
+
function formatFileSize(bytes) {
|
|
155
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
156
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
157
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
158
|
+
}
|
|
159
|
+
function formatDate(date) {
|
|
160
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
161
|
+
return d.toLocaleString();
|
|
162
|
+
}
|
|
163
|
+
function getCredentialsHint(tenant) {
|
|
164
|
+
return `Use: farseer login
|
|
165
|
+
Or: farseer config set ${tenant} --api-key <key> --org <organisation>`;
|
|
166
|
+
}
|
|
167
|
+
function resolveOrgAndTenant(tenantArg) {
|
|
168
|
+
if (tenantArg) {
|
|
169
|
+
return { organisation: tenantArg, tenant: tenantArg };
|
|
170
|
+
}
|
|
171
|
+
const checkout = (0, import_configService.getCurrentCheckout)();
|
|
172
|
+
if (checkout) {
|
|
173
|
+
if (checkout.organisation === checkout.tenant) {
|
|
174
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant}`);
|
|
175
|
+
} else {
|
|
176
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant} (org: ${checkout.organisation})`);
|
|
177
|
+
}
|
|
178
|
+
return checkout;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
function resolveTenant(tenantArg) {
|
|
183
|
+
const resolved = resolveOrgAndTenant(tenantArg);
|
|
184
|
+
return resolved?.tenant || null;
|
|
185
|
+
}
|
|
186
|
+
function resolveTenantOrExit(tenantArg) {
|
|
187
|
+
const tenant = resolveTenant(tenantArg);
|
|
188
|
+
if (!tenant) {
|
|
189
|
+
import_logger.logger.error("No tenant specified.");
|
|
190
|
+
import_logger.logger.dim("Either specify a tenant: farseer <command> <tenant>");
|
|
191
|
+
import_logger.logger.dim("Or checkout a tenant: farseer checkout <tenant>");
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
return tenant;
|
|
195
|
+
}
|
|
196
|
+
function resolveTenantWithOrgMapping(arg1, arg2) {
|
|
197
|
+
if (arg1 && arg2) {
|
|
198
|
+
const org = arg1;
|
|
199
|
+
const tenant = arg2;
|
|
200
|
+
(0, import_configService.saveTenantOrgMapping)(tenant, org);
|
|
201
|
+
if (org === tenant) {
|
|
202
|
+
import_logger.logger.dim(`Using tenant: ${tenant}`);
|
|
203
|
+
} else {
|
|
204
|
+
import_logger.logger.dim(`Using tenant: ${tenant} (org: ${org})`);
|
|
205
|
+
}
|
|
206
|
+
return { organisation: org, tenant };
|
|
207
|
+
}
|
|
208
|
+
if (arg1) {
|
|
209
|
+
const tenant = arg1;
|
|
210
|
+
const savedOrg = (0, import_configService.getTenantOrg)(tenant);
|
|
211
|
+
if (savedOrg) {
|
|
212
|
+
if (savedOrg === tenant) {
|
|
213
|
+
import_logger.logger.dim(`Using tenant: ${tenant} (from saved mapping)`);
|
|
214
|
+
} else {
|
|
215
|
+
import_logger.logger.dim(`Using tenant: ${tenant} (org: ${savedOrg}, from saved mapping)`);
|
|
216
|
+
}
|
|
217
|
+
return { organisation: savedOrg, tenant };
|
|
218
|
+
}
|
|
219
|
+
import_logger.logger.error(`Organisation unknown for tenant "${tenant}".`);
|
|
220
|
+
import_logger.logger.dim("Please specify both organisation and tenant:");
|
|
221
|
+
import_logger.logger.dim(` farseer <command> <organisation> <tenant>`);
|
|
222
|
+
import_logger.logger.dim(` Example: farseer pull jgl tt-hotels-hr-dev`);
|
|
223
|
+
import_logger.logger.dim("");
|
|
224
|
+
import_logger.logger.dim("Or checkout the tenant first:");
|
|
225
|
+
import_logger.logger.dim(` farseer checkout <organisation> <tenant>`);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
const checkout = (0, import_configService.getCurrentCheckout)();
|
|
229
|
+
if (checkout) {
|
|
230
|
+
if (checkout.organisation === checkout.tenant) {
|
|
231
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant}`);
|
|
232
|
+
} else {
|
|
233
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant} (org: ${checkout.organisation})`);
|
|
234
|
+
}
|
|
235
|
+
return checkout;
|
|
236
|
+
}
|
|
237
|
+
import_logger.logger.error("No tenant specified.");
|
|
238
|
+
import_logger.logger.dim("Either specify organisation and tenant: farseer <command> <org> <tenant>");
|
|
239
|
+
import_logger.logger.dim("Or checkout a tenant: farseer checkout <org> <tenant>");
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
function resolveOrgAndTenantOrExit(tenantArg) {
|
|
243
|
+
const resolved = resolveOrgAndTenant(tenantArg);
|
|
244
|
+
if (!resolved) {
|
|
245
|
+
import_logger.logger.error("No tenant specified.");
|
|
246
|
+
import_logger.logger.dim("Either specify a tenant: farseer <command> <tenant>");
|
|
247
|
+
import_logger.logger.dim("Or checkout a tenant: farseer checkout <tenant>");
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
return resolved;
|
|
251
|
+
}
|
|
252
|
+
function isKnownTenant(name) {
|
|
253
|
+
const { getCredential } = require("../services/configService");
|
|
254
|
+
return !!getCredential(name);
|
|
255
|
+
}
|
|
256
|
+
function parseAppArgs(args) {
|
|
257
|
+
if (args.length === 0) {
|
|
258
|
+
import_logger.logger.error("App name is required.");
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
if (args.length >= 2 && isKnownTenant(args[0])) {
|
|
262
|
+
return {
|
|
263
|
+
organisation: args[0],
|
|
264
|
+
tenant: args[0],
|
|
265
|
+
appName: args.slice(1).join(" ")
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
const checkout = (0, import_configService.getCurrentCheckout)();
|
|
269
|
+
if (checkout) {
|
|
270
|
+
if (checkout.organisation === checkout.tenant) {
|
|
271
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant}`);
|
|
272
|
+
} else {
|
|
273
|
+
import_logger.logger.dim(`Using checked-out tenant: ${checkout.tenant} (org: ${checkout.organisation})`);
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
organisation: checkout.organisation,
|
|
277
|
+
tenant: checkout.tenant,
|
|
278
|
+
appName: args.join(" ")
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (args.length >= 2) {
|
|
282
|
+
return {
|
|
283
|
+
organisation: args[0],
|
|
284
|
+
tenant: args[0],
|
|
285
|
+
appName: args.slice(1).join(" ")
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
import_logger.logger.error("No tenant specified.");
|
|
289
|
+
import_logger.logger.dim("Either specify a tenant: farseer app show <tenant> <app-name>");
|
|
290
|
+
import_logger.logger.dim("Or checkout a tenant: farseer checkout <tenant>");
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
const EMPTY_CLIENT_PATTERNS = [
|
|
294
|
+
/const farseerClient = new farseer\.FarseerClient\(\s*\);/g,
|
|
295
|
+
/const fClient = new farseer\.FarseerClient\(\s*\);/g
|
|
296
|
+
];
|
|
297
|
+
const INJECTED_CLIENT_PATTERN = /const (farseerClient|fClient) = new farseer\.FarseerClient\(\{[\s\S]*?basePath:[\s\S]*?headers:[\s\S]*?'X-TENANT-ID':[\s\S]*?'X-API-KEY':[\s\S]*?\}\);/g;
|
|
298
|
+
function injectCredentials(code, credential) {
|
|
299
|
+
const clientConfig = `{
|
|
300
|
+
basePath: '${credential.basePath}',
|
|
301
|
+
headers: {
|
|
302
|
+
'X-TENANT-ID': '${credential.tenantId}',
|
|
303
|
+
'X-API-KEY': '${credential.apiKey}',
|
|
304
|
+
}
|
|
305
|
+
}`;
|
|
306
|
+
let modified = code;
|
|
307
|
+
modified = modified.replace(
|
|
308
|
+
/const farseerClient = new farseer\.FarseerClient\(\s*\);/g,
|
|
309
|
+
`const farseerClient = new farseer.FarseerClient(${clientConfig});`
|
|
310
|
+
);
|
|
311
|
+
modified = modified.replace(
|
|
312
|
+
/const fClient = new farseer\.FarseerClient\(\s*\);/g,
|
|
313
|
+
`const fClient = new farseer.FarseerClient(${clientConfig});`
|
|
314
|
+
);
|
|
315
|
+
return modified;
|
|
316
|
+
}
|
|
317
|
+
function stripCredentials(code) {
|
|
318
|
+
let modified = code;
|
|
319
|
+
modified = modified.replace(
|
|
320
|
+
/const farseerClient = new farseer\.FarseerClient\(\{[\s\S]*?basePath:[\s\S]*?headers:[\s\S]*?'X-TENANT-ID':[\s\S]*?'X-API-KEY':[\s\S]*?\}\);/g,
|
|
321
|
+
"const farseerClient = new farseer.FarseerClient();"
|
|
322
|
+
);
|
|
323
|
+
modified = modified.replace(
|
|
324
|
+
/const fClient = new farseer\.FarseerClient\(\{[\s\S]*?basePath:[\s\S]*?headers:[\s\S]*?'X-TENANT-ID':[\s\S]*?'X-API-KEY':[\s\S]*?\}\);/g,
|
|
325
|
+
"const fClient = new farseer.FarseerClient();"
|
|
326
|
+
);
|
|
327
|
+
return modified;
|
|
328
|
+
}
|
|
329
|
+
function hasInjectedCredentials(code) {
|
|
330
|
+
return INJECTED_CLIENT_PATTERN.test(code);
|
|
331
|
+
}
|
|
332
|
+
function hasEmptyFarseerClient(code) {
|
|
333
|
+
return EMPTY_CLIENT_PATTERNS.some((pattern) => pattern.test(code));
|
|
334
|
+
}
|
|
335
|
+
function injectCredentialsInDir(srcDir, credential) {
|
|
336
|
+
let count = 0;
|
|
337
|
+
const files = getAllFiles(srcDir);
|
|
338
|
+
for (const file of files) {
|
|
339
|
+
const filePath = path.join(srcDir, file);
|
|
340
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
341
|
+
const modified = injectCredentials(content, credential);
|
|
342
|
+
if (modified !== content) {
|
|
343
|
+
fs.writeFileSync(filePath, modified);
|
|
344
|
+
count++;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return count;
|
|
348
|
+
}
|
|
349
|
+
function stripCredentialsInDir(srcDir) {
|
|
350
|
+
let count = 0;
|
|
351
|
+
const files = getAllFiles(srcDir);
|
|
352
|
+
for (const file of files) {
|
|
353
|
+
const filePath = path.join(srcDir, file);
|
|
354
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
355
|
+
const modified = stripCredentials(content);
|
|
356
|
+
if (modified !== content) {
|
|
357
|
+
fs.writeFileSync(filePath, modified);
|
|
358
|
+
count++;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return count;
|
|
362
|
+
}
|
|
363
|
+
function appendToAuditLog(tenant, entries) {
|
|
364
|
+
if (entries.length === 0) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const logPath = getAuditLogPath(tenant);
|
|
368
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
369
|
+
let logContent = "";
|
|
370
|
+
for (const entry of entries) {
|
|
371
|
+
const uploaderInfo = entry.uploaderName ? `${entry.uploaderName} (${entry.uploaderEmail})` : entry.uploaderEmail || "Unknown";
|
|
372
|
+
const uploadedAt = entry.uploadTime ? new Date(entry.uploadTime).toLocaleString() : "Unknown";
|
|
373
|
+
logContent += `${timestamp} | ${entry.operation} | ${entry.filePath} | Modified by: ${uploaderInfo} | Uploaded: ${uploadedAt}
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
fs.appendFileSync(logPath, logContent, "utf-8");
|
|
377
|
+
}
|
|
378
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
379
|
+
0 && (module.exports = {
|
|
380
|
+
appendToAuditLog,
|
|
381
|
+
calculateHash,
|
|
382
|
+
ensureDirectoryExists,
|
|
383
|
+
formatDate,
|
|
384
|
+
formatFileSize,
|
|
385
|
+
getAllFiles,
|
|
386
|
+
getAllFilesInDir,
|
|
387
|
+
getAppsDir,
|
|
388
|
+
getAuditLogPath,
|
|
389
|
+
getCredentialsHint,
|
|
390
|
+
getRelativePath,
|
|
391
|
+
getSyncFilePath,
|
|
392
|
+
getTenantAppsDir,
|
|
393
|
+
getTenantDir,
|
|
394
|
+
getTenantFilesDir,
|
|
395
|
+
getTenantSrcDir,
|
|
396
|
+
hasEmptyFarseerClient,
|
|
397
|
+
hasInjectedCredentials,
|
|
398
|
+
injectCredentials,
|
|
399
|
+
injectCredentialsInDir,
|
|
400
|
+
isInRemotejobsRepo,
|
|
401
|
+
isKnownTenant,
|
|
402
|
+
isScriptFile,
|
|
403
|
+
isTextFile,
|
|
404
|
+
parseAppArgs,
|
|
405
|
+
resolveOrgAndTenant,
|
|
406
|
+
resolveOrgAndTenantOrExit,
|
|
407
|
+
resolveTenant,
|
|
408
|
+
resolveTenantOrExit,
|
|
409
|
+
resolveTenantWithOrgMapping,
|
|
410
|
+
stripCredentials,
|
|
411
|
+
stripCredentialsInDir
|
|
412
|
+
});
|
|
413
|
+
//# sourceMappingURL=helpers.js.map
|