{"_id":"@azumaxoid/newrelic-instrument-annotation","_rev":"4-f7b8543f25ba685f98dc7abaef0eb2cf","name":"@azumaxoid/newrelic-instrument-annotation","dist-tags":{"latest":"0.3.0"},"versions":{"0.0.0":{"name":"@azumaxoid/newrelic-instrument-annotation","version":"0.0.0","author":{"name":"Azumaxoid"},"license":"MIT","_id":"@azumaxoid/newrelic-instrument-annotation@0.0.0","maintainers":[{"name":"azumaxoid","email":"azumax.android@gmail.com"}],"homepage":"https://github.com/Azumaxoid/newrelic-instrument-annotation#readme","bugs":{"url":"https://github.com/Azumaxoid/newrelic-instrument-annotation/issues"},"dist":{"shasum":"eb793f8ba83c75928ba32e988417aeeafa3e2e28","tarball":"https://registry.npmjs.org/@azumaxoid/newrelic-instrument-annotation/-/newrelic-instrument-annotation-0.0.0.tgz","fileCount":9,"integrity":"sha512-hGcQqJkcZeRpvS4CDyloYhRBgZ0GPxs4tSGXh2/DgwKZO2Cx6iQz4ByW8KtBhnCv8AGAGTlt92NKG0Po9w49XQ==","signatures":[{"sig":"MEUCIQDu4TfJS3ReoDkYJUhW8yLWio5JNX6xIf17I2meBJidIgIgWg3DYNAAqSHAW/p5lDNBiQ7D+u+ehdObb84VG8lm5ZM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58969},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"34f33485f16422c9dbb833c60bde6dfcbe9a850d","scripts":{"dev":"tsup --watch","lint":"eslint src test","test":"jest","build":"tsup","release":"npm run build && changeset publish","changeset":"changeset","typecheck":"tsc --noEmit","test:coverage":"jest --coverage","prepublishOnly":"npm run build","version-packages":"changeset version"},"_npmUser":{"name":"azumaxoid","email":"azumax.android@gmail.com"},"repository":{"url":"git+https://github.com/Azumaxoid/newrelic-instrument-annotation.git","type":"git"},"_npmVersion":"11.3.0","description":"Decorator-based New Relic APM instrumentation for TypeScript service classes","directories":{},"_nodeVersion":"24.1.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","tsup":"^8.3.0","eslint":"^9.0.0","ts-jest":"^29.2.0","newrelic":"^14.1.2","typescript":"^5.7.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@changesets/cli":"^2.27.0","@types/newrelic":"^9.14.8","typescript-eslint":"^8.0.0"},"peerDependencies":{"newrelic":"^14.1.2"},"peerDependenciesMeta":{"newrelic":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/newrelic-instrument-annotation_0.0.0_1785306075233_0.15327504761654165","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@azumaxoid/newrelic-instrument-annotation","version":"0.1.0","author":{"name":"Azumaxoid"},"license":"MIT","_id":"@azumaxoid/newrelic-instrument-annotation@0.1.0","maintainers":[{"name":"azumaxoid","email":"azumax.android@gmail.com"}],"homepage":"https://github.com/Azumaxoid/newrelic-instrument-annotation#readme","bugs":{"url":"https://github.com/Azumaxoid/newrelic-instrument-annotation/issues"},"dist":{"shasum":"176169d138fe697e32537f6395d09d572c8684d6","tarball":"https://registry.npmjs.org/@azumaxoid/newrelic-instrument-annotation/-/newrelic-instrument-annotation-0.1.0.tgz","fileCount":9,"integrity":"sha512-4cjZrz9+jp71nMroe8nEcYMZgqCVcsDyabUTQISE2Hf0OagUAtA/VAGd4MQZoSDXOfRg1Visqkx7Gf65LyJzkg==","signatures":[{"sig":"MEQCIBDUHgzp+iGAlogbbCnV8TgIKFZF5KXyCxhwQ/nlYxJDAiA6ewUo+y7lD1jK2hQK+sWXjeIHu1FK0EUn097e0O3qdg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@azumaxoid%2fnewrelic-instrument-annotation@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":58969},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"4bf0eaf4f58b6b0b1e745b2b8bcd6071096db2e4","scripts":{"dev":"tsup --watch","lint":"eslint src test","test":"jest","build":"tsup","release":"npm run build && changeset publish","changeset":"changeset","typecheck":"tsc --noEmit","test:coverage":"jest --coverage","prepublishOnly":"npm run build","version-packages":"changeset version"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:24663eac-6fc5-43e4-a47d-49d99574d491"}},"repository":{"url":"git+https://github.com/Azumaxoid/newrelic-instrument-annotation.git","type":"git"},"_npmVersion":"11.16.0","description":"Decorator-based New Relic APM instrumentation for TypeScript service classes","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","tsup":"^8.3.0","eslint":"^9.0.0","ts-jest":"^29.2.0","newrelic":"^14.1.2","typescript":"^5.7.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@changesets/cli":"^2.27.0","@types/newrelic":"^9.14.8","typescript-eslint":"^8.0.0"},"peerDependencies":{"newrelic":"^14.1.2"},"peerDependenciesMeta":{"newrelic":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/newrelic-instrument-annotation_0.1.0_1785313195617_0.2164975472900068","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@azumaxoid/newrelic-instrument-annotation","version":"0.2.0","author":{"name":"Azumaxoid"},"license":"MIT","_id":"@azumaxoid/newrelic-instrument-annotation@0.2.0","maintainers":[{"name":"azumaxoid","email":"azumax.android@gmail.com"}],"homepage":"https://github.com/Azumaxoid/newrelic-instrument-annotation#readme","bugs":{"url":"https://github.com/Azumaxoid/newrelic-instrument-annotation/issues"},"dist":{"shasum":"d8aec889b7474fac4aac606444170411712ce0be","tarball":"https://registry.npmjs.org/@azumaxoid/newrelic-instrument-annotation/-/newrelic-instrument-annotation-0.2.0.tgz","fileCount":9,"integrity":"sha512-Nyuaiu0kMBfx3G3R0FTj41lk4T/luM90zQH5GMnNqliwvs0SiR+bAdDl6oTkNl/u3at42bkcNIBXQDw1HrY8Bg==","signatures":[{"sig":"MEUCIDZafERCk4Ujc1Rfi7kaoxAEmMRa5szPZgxtZ1E8JY8MAiEA4pJxrOgCbC5sm/ocEW9FvXWSRPKUAHVXuJPSB0RWkLk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@azumaxoid%2fnewrelic-instrument-annotation@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":91782},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"858a9c42e0d69fe34872da665570b14d7430c05d","scripts":{"dev":"tsup --watch","lint":"eslint src test","test":"jest","build":"tsup","release":"npm run build && changeset publish","changeset":"changeset","typecheck":"tsc --noEmit","test:coverage":"jest --coverage","prepublishOnly":"npm run build","version-packages":"changeset version"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:24663eac-6fc5-43e4-a47d-49d99574d491"}},"repository":{"url":"git+https://github.com/Azumaxoid/newrelic-instrument-annotation.git","type":"git"},"_npmVersion":"11.16.0","description":"Decorator-based New Relic APM instrumentation for TypeScript service classes","directories":{},"_nodeVersion":"24.18.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","tsup":"^8.3.0","eslint":"^9.0.0","ts-jest":"^29.2.0","newrelic":"^14.1.2","typescript":"^5.7.0","@types/jest":"^29.5.0","@types/node":"^20.0.0","@changesets/cli":"^2.27.0","@types/newrelic":"^9.14.8","typescript-eslint":"^8.0.0"},"peerDependencies":{"newrelic":"^14.1.2"},"peerDependenciesMeta":{"newrelic":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/newrelic-instrument-annotation_0.2.0_1785458441506_0.5913885928643201","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@azumaxoid/newrelic-instrument-annotation","version":"0.3.0","description":"Decorator-based New Relic APM instrumentation for TypeScript service classes","license":"MIT","author":{"name":"Azumaxoid"},"repository":{"type":"git","url":"git+https://github.com/Azumaxoid/newrelic-instrument-annotation.git"},"main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"engines":{"node":">=18"},"scripts":{"build":"tsup","dev":"tsup --watch","lint":"eslint src test","typecheck":"tsc --noEmit","test":"jest","test:coverage":"jest --coverage","prepublishOnly":"npm run build","changeset":"changeset","version-packages":"changeset version","release":"npm run build && changeset publish"},"peerDependencies":{"newrelic":"^14.1.2"},"peerDependenciesMeta":{"newrelic":{"optional":false}},"devDependencies":{"@changesets/cli":"^2.27.0","@types/jest":"^29.5.0","@types/newrelic":"^9.14.8","@types/node":"^20.0.0","eslint":"^9.0.0","jest":"^29.7.0","newrelic":"^14.1.2","ts-jest":"^29.2.0","tsup":"^8.3.0","typescript":"^5.7.0","typescript-eslint":"^8.0.0"},"publishConfig":{"access":"public"},"gitHead":"d070ea5d3d971351cb3b8267d2180008e13300f2","_id":"@azumaxoid/newrelic-instrument-annotation@0.3.0","bugs":{"url":"https://github.com/Azumaxoid/newrelic-instrument-annotation/issues"},"homepage":"https://github.com/Azumaxoid/newrelic-instrument-annotation#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-SIb0vtU1ahK+X7S1w0gdcj5ylT6gDmFc514LdSk5eBN9CRu8P3fi0QmkYpF0xMuG1MqR41r5R6fFlasbEWxQwg==","shasum":"11d42f7316cf75403302313224ad7e238f52017c","tarball":"https://registry.npmjs.org/@azumaxoid/newrelic-instrument-annotation/-/newrelic-instrument-annotation-0.3.0.tgz","fileCount":9,"unpackedSize":99806,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@azumaxoid%2fnewrelic-instrument-annotation@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIAGpQM1hdZtDcOUyx2B/5RTp15cT/PGAQEwbFM+p1BcBAiAO8Udq0kGIfkpqSosN07dQ/Pq+L0jHzI8KkPBoo5UGVg=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:24663eac-6fc5-43e4-a47d-49d99574d491"}},"directories":{},"maintainers":[{"name":"azumaxoid","email":"azumax.android@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/newrelic-instrument-annotation_0.3.0_1785472885995_0.3683096227964886"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-29T06:21:15.066Z","modified":"2026-07-31T04:41:26.490Z","0.0.0":"2026-07-29T06:21:15.382Z","0.1.0":"2026-07-29T08:19:55.785Z","0.2.0":"2026-07-31T00:40:41.781Z","0.3.0":"2026-07-31T04:41:26.150Z"},"bugs":{"url":"https://github.com/Azumaxoid/newrelic-instrument-annotation/issues"},"author":{"name":"Azumaxoid"},"license":"MIT","homepage":"https://github.com/Azumaxoid/newrelic-instrument-annotation#readme","repository":{"type":"git","url":"git+https://github.com/Azumaxoid/newrelic-instrument-annotation.git"},"description":"Decorator-based New Relic APM instrumentation for TypeScript service classes","maintainers":[{"name":"azumaxoid","email":"azumax.android@gmail.com"}],"readme":"# @azumaxoid/newrelic-instrument-annotation\n\nA decorator-based utility that applies New Relic APM auto-instrumentation\n(per-method segment tracing + error notification) to TypeScript service classes.\n\n## Features\n\n- Automatically wraps every public method of a class with `newrelic.startSegment`\n- Supports both synchronous methods and methods returning a `Promise`\n- Automatically calls `newrelic.noticeError` when an exception is thrown\n- Prevents duplicate reporting of the same error when one instrumented method\n  calls another instrumented method on the same class (e.g. `post` → `executePost`)\n- Method arguments are **not** collected as attributes automatically, even when\n  an error is reported. Use the `@CollectAttributes` decorator to opt specific\n  arguments in explicitly, with an optional per-attribute SHA-256 hash.\n\n## Installation\n\n```bash\nnpm install @azumaxoid/newrelic-instrument-annotation\n```\n\n`newrelic` (the New Relic Node.js agent) is a `peerDependency`. This package\nuses the `newrelic` package (`^14.1.2`) already installed in the host\napplication.\n\n## Usage\n\n### As a class decorator (`@InstrumentService`)\n\n```typescript\nimport { InstrumentService } from '@azumaxoid/newrelic-instrument-annotation';\n\n@InstrumentService('MyService')\nclass MyService {\n  async fetchData(id: string) {\n    // ...\n  }\n}\n```\n\n### Logger injection\n\nBy default, internal logs are written to `console`, but you can inject any\nlogger of your own. Any object implementing `info`/`warn`/`error` methods\n(`LoggerLike`) can be used.\n\n```typescript\nimport { InstrumentService, LoggerLike } from '@azumaxoid/newrelic-instrument-annotation';\n\nconst myLogger: LoggerLike = {\n  info: (msg, meta) => console.log('[INFO]', msg, meta),\n  warn: (msg, meta) => console.warn('[WARN]', msg, meta),\n  error: (msg, meta) => console.error('[ERROR]', msg, meta),\n};\n\n@InstrumentService('MyService', { logger: myLogger })\nclass MyService { /* ... */ }\n```\n\n### Collecting method arguments as attributes (`@CollectAttributes`)\n\nBy default, no method argument is sent to New Relic — not even when an error\nis reported. This is a deliberate security-driven default: earlier versions\nsent every argument automatically, which risked leaking PII/secrets into\nerror attributes. To opt specific arguments in explicitly, add\n`@CollectAttributes` to a method. Entries are mapped **positionally** to the\nmethod's arguments (the first entry corresponds to the first argument, and so\non).\n\n**Example use case:** correlate errors by user without exposing PII, by\nhashing the identifier instead of sending it as-is:\n\n```typescript\nclass UserService {\n  @CollectAttributes([{ name: 'userIdHash', hash: true }])\n  async fetchUser(userId: string) {\n    // ...\n  }\n}\n```\n\n`userIdHash` lets you group/search errors for the same user in New Relic\nwithout the raw `userId` ever leaving the process.\n\n```typescript\nimport { InstrumentService, CollectAttributes } from '@azumaxoid/newrelic-instrument-annotation';\n\n@InstrumentService('UserService')\nclass UserService {\n  @CollectAttributes(['userId', { name: 'email', hash: true }])\n  async fetchUser(userId: string, email: string) {\n    // ...\n  }\n}\n```\n\n- A plain string (e.g. `'userId'`) uses that string as both the source\n  position's label and the resulting New Relic attribute name, with no hashing.\n- An object (`{ name: string, hash?: boolean }`) lets you rename the attribute\n  and/or hash its value.\n- `hash: true` replaces the value with its SHA-256 hex digest before sending it.\n- Arguments that are `undefined`/`null` at a declared position are omitted\n  from the resulting attributes.\n\nBy default (`when: 'error'`), declared attributes are attached only to the\n`noticeError` call made when the method throws or its returned `Promise`\nrejects. Pass `{ when: 'always' }` to also attach them to the current\ntransaction via `newrelic.addCustomAttributes` on every call, regardless of\nsuccess or failure:\n\n```typescript\nclass UserService {\n  @CollectAttributes(['userId'], { when: 'always' })\n  async fetchUser(userId: string) {\n    // ...\n  }\n}\n```\n\n#### Skipping a leading/middle argument with `null`\n\nEntries map positionally, so if a method's first (or middle) argument is a\nnon-primitive value you don't want to collect (e.g. `session`), pass `null`\nfor that position. This keeps every later entry correctly aligned with its\ncorresponding argument:\n\n```typescript\nclass UserService {\n  @CollectAttributes([null, { name: 'email', hash: true }])\n  async fetchUser(session: Session, email: string) {\n    // ...\n  }\n}\n```\n\nHere `session` (position 0) is never collected, while `email` (position 1)\nis hashed and sent as usual. `null` entries can appear anywhere in the array,\nincluding consecutively (`[null, null, 'criterianame']`) or between two\ncollected entries (`['attemptid', null, 'page']`).\n\n### Using `stringifyArgsForTelemetry` directly (masking utility)\n\n`stringifyArgsForTelemetry` is a standalone masking + serialization utility.\nIt is no longer called automatically by the instrumentation wrapper — use it\nyourself if you need to log/serialize arguments elsewhere.\n\n```typescript\nimport { stringifyArgsForTelemetry } from '@azumaxoid/newrelic-instrument-annotation';\n\nstringifyArgsForTelemetry([{ token: 'secret-value', name: 'ok' }]);\n// => '[{\"token\":\"[REDACTED]\",\"name\":\"ok\"}]'\n```\n\nNote: unlike the key-name masking above, `@CollectAttributes` does **not**\napply any automatic masking — it trusts that you only declare attributes that\nare safe to send (use `hash: true` if a value still needs protecting).\n\n## How it works\n\n- Methods named `constructor` or starting with `_` are excluded from instrumentation.\n- When an error is reported, `reported = true` is set on the error object.\n  This is intended to be combined with a host application's outermost error\n  handler that checks `error.reported` to avoid re-reporting (this package\n  itself does not depend on such a handler existing).\n- When the same Error object propagates through multiple layers of nested\n  instrumented method calls, a `WeakSet` ensures `noticeError` is only called\n  from the innermost layer.\n\n## API Reference\n\n- `InstrumentService(serviceName: string, options?: InstrumentServiceOptions)` — class decorator\n- `instrumentServiceClass<T>(ServiceClass: T, serviceName: string, options?: InstrumentServiceOptions): T` — the function backing the decorator\n- `instrumentMethod(target, methodName, serviceName, options?)` — manual instrumentation of a single method\n- `CollectAttributes(attributes: AttributeDefinition[], options?: CollectAttributesOptions)` — method decorator that opts specific arguments into attribute collection (positional mapping, `null` entries to skip a position, optional per-attribute SHA-256 hashing, `when: 'error' | 'always'`)\n- `getAttributeCollectionConfig(target: object, methodName: string): AttributeCollectionConfig | undefined` — looks up the `@CollectAttributes` config registered for a prototype/method pair; exposed so other instrumentation layers (e.g. an OpenTelemetry shim) can build the same attribute set from the same declarations\n- `collectAttributesFromArgs(config: AttributeCollectionConfig, args: unknown[]): Record<string, string | number | boolean>` — builds an attributes object from an argument list per a resolved config; exposed for the same cross-instrumentation reuse case as `getAttributeCollectionConfig`\n- `stringifyArgsForTelemetry(args: unknown[], maxLength?: number): string` — argument masking + JSON stringification (standalone utility)\n- `LoggerLike` / `InstrumentServiceOptions` — type definitions\n- `AttributeDefinition` / `CollectAttributesOptions` / `AttributeCollectionWhen` / `AttributeCollectionConfig` / `NormalizedAttributeDefinition` — type definitions for `@CollectAttributes`\n\n## Contributing\n\nPlease use [Changesets](https://github.com/changesets/changesets) when making changes.\n\n```bash\nnpx changeset\n```\n\nOnce a PR containing a `.changeset/*.md` file is merged into `main`, CI will\nautomatically open a version-bump PR; merging that PR publishes the new\nversion to npm.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}