diff --git a/package-lock.json b/package-lock.json index fc665ff2..795b5656 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "grunt-contrib-watch": "^1.1.0", "grunt-string-replace": "^1.3.3", "jasmine": "^5.8.0", + "typescript": "^5.8.3", "underscore": "^1.13.7" } }, @@ -10399,6 +10400,20 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", diff --git a/package.json b/package.json index 62d75c08..f4f10836 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,12 @@ "grunt-contrib-watch": "^1.1.0", "grunt-string-replace": "^1.3.3", "jasmine": "^5.8.0", + "typescript": "^5.8.3", "underscore": "^1.13.7" }, "scripts": { "test": "npm run jasmine && npm run wdio", - "jasmine": "jasmine --config=jasmine.json", + "jasmine": "jasmine --config=jasmine.json && jasmine tests/specs/typescript-definitions.js", "wdio": "cross-env node_modules/.bin/wdio wdio.conf.js" }, "keywords": [ diff --git a/tests/specs/typescript-definitions.js b/tests/specs/typescript-definitions.js new file mode 100644 index 00000000..a02beaeb --- /dev/null +++ b/tests/specs/typescript-definitions.js @@ -0,0 +1,23 @@ +/* globals describe, it, expect */ + +var { exec } = require('child_process'); +var path = require('path'); + +describe("TypeScript Definitions", function() { + it("should compile without errors", function(done) { + var tsFile = path.join(__dirname, '../types-test.ts'); + var cmd = 'npx tsc --noEmit ' + tsFile + ' --strict'; + + exec(cmd, function(error, stdout, stderr) { + if (error) { + console.error('TypeScript compilation failed:', error); + console.error('stdout:', stdout); + console.error('stderr:', stderr); + expect(error).toBeNull(); + } else { + console.log('TypeScript compilation succeeded'); + } + done(); + }); + }); +}); diff --git a/tests/types-test.ts b/tests/types-test.ts new file mode 100644 index 00000000..ca042fc7 --- /dev/null +++ b/tests/types-test.ts @@ -0,0 +1,92 @@ +import { RaygunPayload, RaygunStatic } from '../types/index'; + +// Test RaygunPayload interface +function testPayloadStructure(): void { + const payload: RaygunPayload = { + OccurredOn: new Date(), + Details: { + Error: { + ClassName: 'Error', + Message: 'Test error', + StackTrace: [] + }, + Environment: { + UtcOffset: 0, + "User-Language": 'en-US', + "Document-Mode": 11, + "Browser-Width": 1920, + "Browser-Height": 1080, + "Screen-Width": 1920, + "Screen-Height": 1080, + "Color-Depth": 24, + Browser: 'Chrome', + "Browser-Name": 'Chrome', + "Browser-Version": '120.0.0', + Platform: 'Linux' + }, + Client: { + Name: 'raygun4js', + Version: '3.1.3' + }, + UserCustomData: {}, + Tags: [], + Request: { + Url: 'https://example.com', + QueryString: '', + Headers: { + "User-Agent": 'Mozilla/5.0', + Referer: 'https://example.com', + Host: 'example.com' + } + }, + Version: '1.0.0', + User: { + Identifier: 'test-user', + IsAnonymous: false, + Email: 'test@example.com', + FullName: 'Test User', + FirstName: 'Test', + UUID: 'test-uuid' + }, + GroupingKey: 'test-group', + Breadcrumbs: [ + { + type: 'manual', + message: 'Test breadcrumb', + level: 'info', + metadata: { test: true } + } + ] + } + }; +} + +// Test that onBeforeSend callback can access and modify breadcrumbs +function testOnBeforeSendBreadcrumbAccess(): void { + // Mock Raygun instance + const raygun = {} as RaygunStatic; + + // This should compile without TypeScript errors + raygun.onBeforeSend((payload: RaygunPayload) => { + // Access breadcrumbs + if (payload.Details.Breadcrumbs) { + // Filter out sensitive breadcrumbs + payload.Details.Breadcrumbs = payload.Details.Breadcrumbs.filter(breadcrumb => { + return breadcrumb.message !== 'sensitive-operation'; + }); + + // Sanitize breadcrumb messages + payload.Details.Breadcrumbs = payload.Details.Breadcrumbs.map(breadcrumb => ({ + ...breadcrumb, + message: breadcrumb.message?.replace(/password|secret|token/gi, '[REDACTED]') + })); + } + + return payload; + }); +} + +export { + testPayloadStructure, + testOnBeforeSendBreadcrumbAccess, +}; diff --git a/types/index.d.ts b/types/index.d.ts index e292d340..57a76796 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -23,6 +23,13 @@ interface RaygunStackTrace { MethodName: string; } +interface RaygunBreadcrumb { + type?: string; + message?: string; + level?: BreadcrumbLevel; + metadata?: any; +} + interface RaygunOptions { /** * Posts error payloads over HTTP. This allows IE8 to send JS errors. @@ -171,6 +178,7 @@ interface RaygunPayload { UUID?: any; }; GroupingKey?: string | undefined; + Breadcrumbs?: RaygunBreadcrumb[]; }; } @@ -432,6 +440,6 @@ interface Window { Raygun: RaygunStatic; } -export { BreadcrumbLevel, RaygunOptions, RaygunPayload, RaygunStackTrace, RaygunStatic, RaygunV2, RaygunV2UserDetails }; +export { BreadcrumbLevel, RaygunBreadcrumb, RaygunOptions, RaygunPayload, RaygunStackTrace, RaygunStatic, RaygunV2, RaygunV2UserDetails }; export default rg4js;