{"_id":"@apexdevtools/apex-log-parser","_rev":"2-6aea4a2ce1d0708f2ff2d785617297ea","name":"@apexdevtools/apex-log-parser","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@apexdevtools/apex-log-parser","version":"0.1.0","keywords":["salesforce","salesforce-apex","apex","sfdc","debug-log","debug-logs","apex-log","apex-logs","parser","log-parser","soql","dml","governor-limits","log-analysis","call-tree","performance","developer-tools","typescript"],"author":{"name":"Certinia Inc."},"license":"BSD-3-Clause","_id":"@apexdevtools/apex-log-parser@0.1.0","maintainers":[{"name":"apexdevtools","email":"apexdevtools@gmail.com"}],"homepage":"https://github.com/apex-dev-tools/apex-log-parser#readme","bugs":{"url":"https://github.com/apex-dev-tools/apex-log-parser/issues"},"dist":{"shasum":"824fdb4ef731dd57ca2d8dc8cd229edebc4a3fa6","tarball":"https://registry.npmjs.org/@apexdevtools/apex-log-parser/-/apex-log-parser-0.1.0.tgz","fileCount":13,"integrity":"sha512-UDIfkvZWJzspW2xvbMo4NEs0o2UfpYLde4O1ShIqM7ZphP8MoYEQ5eriOzNte9SfGZmXaO4l1YKsRltihwGHJA==","signatures":[{"sig":"MEQCIHNBCfuJKiAT3sMkuNa/NLsHFcaaOJa4bBdShi80EPXFAiBSBxAwhhl9zmX1Qf9kUCxmKtGHmIle/IXyXbNoJ7uVng==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@apexdevtools%2fapex-log-parser@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":197231},"main":"./dist/index.js","type":"module","_from":"file:apexdevtools-apex-log-parser-0.1.0.tgz","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./types":{"types":"./dist/publicTypes.d.ts","import":"./dist/publicTypes.js"},"./package.json":"./package.json"},"scripts":{"ci":"biome check . && tsc --noEmit && tsc -p tsconfig.scripts.json && vitest run","lint":"biome check .","test":"vitest run","build":"tsdown && tsc -p tsconfig.build.json","format":"biome format --write .","scrape":"tsx scripts/scrape.ts","ci:seed":"tsx scripts/ci/seed.ts","lint:fix":"biome check --write .","ci:report":"tsx scripts/ci/report.ts","typecheck":"tsc --noEmit","test:watch":"vitest","validate:data":"tsx scripts/validate-data.ts","version:packages":"changeset version && biome check --write package.json","typecheck:scripts":"tsc -p tsconfig.scripts.json"},"_npmUser":{"name":"apexdevtools","email":"apexdevtools@gmail.com"},"_resolved":"/tmp/cf3797a1adf29cd3d0cf47095d85f6b1/apexdevtools-apex-log-parser-0.1.0.tgz","_integrity":"sha512-UDIfkvZWJzspW2xvbMo4NEs0o2UfpYLde4O1ShIqM7ZphP8MoYEQ5eriOzNte9SfGZmXaO4l1YKsRltihwGHJA==","repository":{"url":"git+https://github.com/apex-dev-tools/apex-log-parser.git","type":"git"},"_npmVersion":"11.17.0","description":"Turn a Salesforce Apex debug log into a typed event tree — execution timings, governor limits, SOQL/DML counts. Zero dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"24.19.0","publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"ajv":"^8.20.0","tsx":"^4.23.12","unrun":"^0.3.1","tsdown":"^0.22.14","vitest":"^4.1.11","typescript":"^7.0.2","@types/node":"^26.4.0","ajv-formats":"^3.0.1","@biomejs/biome":"^2.5.10","@changesets/cli":"^3.0.1","node-html-parser":"^9.0.1"},"_npmOperationalInternal":{"tmp":"tmp/apex-log-parser_0.1.0_1788353569812_0.630403419881399","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@apexdevtools/apex-log-parser","version":"0.1.1","description":"Turn a Salesforce Apex debug log into a typed event tree — execution timings, governor limits, SOQL/DML counts. Zero dependencies.","type":"module","sideEffects":false,"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./types":{"types":"./dist/publicTypes.d.ts","import":"./dist/publicTypes.js"},"./package.json":"./package.json"},"main":"./dist/index.js","types":"./dist/index.d.ts","devDependencies":{"@biomejs/biome":"^2.5.11","@changesets/cli":"^3.0.1","@types/node":"^26.4.0","ajv":"^8.20.0","ajv-formats":"^3.0.1","node-html-parser":"^9.0.2","tsdown":"^0.22.14","tsx":"^4.23.13","typescript":"^7.0.2","unrun":"^0.3.1","vitest":"^4.1.11"},"engines":{"node":">=20"},"license":"BSD-3-Clause","author":{"name":"Certinia Inc."},"homepage":"https://github.com/apex-dev-tools/apex-log-parser#readme","repository":{"type":"git","url":"git+https://github.com/apex-dev-tools/apex-log-parser.git"},"bugs":{"url":"https://github.com/apex-dev-tools/apex-log-parser/issues"},"publishConfig":{"provenance":true,"access":"public"},"keywords":["salesforce","salesforce-apex","apex","sfdc","debug-log","debug-logs","apex-log","apex-logs","parser","log-parser","soql","dml","governor-limits","log-analysis","call-tree","performance","developer-tools","typescript"],"scripts":{"build":"tsdown && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","typecheck:scripts":"tsc -p tsconfig.scripts.json","test":"vitest run","test:watch":"vitest","lint":"biome check .","lint:fix":"biome check --write .","format":"biome format --write .","ci":"biome check . && tsc --noEmit && tsc -p tsconfig.scripts.json && vitest run","version:packages":"changeset version && biome check --write package.json","scrape":"tsx scripts/scrape.ts","validate:data":"tsx scripts/validate-data.ts","ci:seed":"tsx scripts/ci/seed.ts","ci:report":"tsx scripts/ci/report.ts"},"_id":"@apexdevtools/apex-log-parser@0.1.1","_integrity":"sha512-8KL/MAo6HsNJJryrV7ujsABRBe4QYXOrpZFzE+2fBZoftqip/9/FYMVufejtcFWWDpwciqVny46kF+ImWYToqw==","_resolved":"/tmp/f5bfdf64187ae80290b63e9c751ea3fc/apexdevtools-apex-log-parser-0.1.1.tgz","_from":"file:apexdevtools-apex-log-parser-0.1.1.tgz","_nodeVersion":"24.20.0","_npmVersion":"11.19.0","dist":{"integrity":"sha512-8KL/MAo6HsNJJryrV7ujsABRBe4QYXOrpZFzE+2fBZoftqip/9/FYMVufejtcFWWDpwciqVny46kF+ImWYToqw==","shasum":"2c2cd2271d99a3a156cdd66a4200a4b307efb4a5","tarball":"https://registry.npmjs.org/@apexdevtools/apex-log-parser/-/apex-log-parser-0.1.1.tgz","fileCount":14,"unpackedSize":198747,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@apexdevtools%2fapex-log-parser@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFteR7d6IhZPZxQF0ny4yWUmnxo39FTCYTgRSpSujp0FAiEAt2jID8rHt1b6FK+lW8wybjOslub4dGh38MQA+++nNv4="}]},"_npmUser":{"name":"apexdevtools","email":"apexdevtools@gmail.com"},"directories":{},"maintainers":[{"name":"apexdevtools","email":"apexdevtools@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/apex-log-parser_0.1.1_1789046568728_0.12991312262447052"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-02T12:52:49.635Z","modified":"2026-09-10T13:22:49.157Z","0.1.0":"2026-09-02T12:52:49.924Z","0.1.1":"2026-09-10T13:22:48.842Z"},"bugs":{"url":"https://github.com/apex-dev-tools/apex-log-parser/issues"},"author":{"name":"Certinia Inc."},"license":"BSD-3-Clause","homepage":"https://github.com/apex-dev-tools/apex-log-parser#readme","keywords":["salesforce","salesforce-apex","apex","sfdc","debug-log","debug-logs","apex-log","apex-logs","parser","log-parser","soql","dml","governor-limits","log-analysis","call-tree","performance","developer-tools","typescript"],"repository":{"type":"git","url":"git+https://github.com/apex-dev-tools/apex-log-parser.git"},"description":"Turn a Salesforce Apex debug log into a typed event tree — execution timings, governor limits, SOQL/DML counts. Zero dependencies.","maintainers":[{"name":"apexdevtools","email":"apexdevtools@gmail.com"}],"readme":"# @apexdevtools/apex-log-parser\n\n[![npm version](https://img.shields.io/npm/v/@apexdevtools/apex-log-parser)](https://www.npmjs.com/package/@apexdevtools/apex-log-parser)\n[![npm downloads](https://img.shields.io/npm/dm/@apexdevtools/apex-log-parser)](https://www.npmjs.com/package/@apexdevtools/apex-log-parser)\n[![minzipped size](https://img.shields.io/bundlephobia/minzip/@apexdevtools/apex-log-parser)](https://bundlephobia.com/package/@apexdevtools/apex-log-parser)\n[![CI](https://github.com/apex-dev-tools/apex-log-parser/actions/workflows/ci.yml/badge.svg)](https://github.com/apex-dev-tools/apex-log-parser/actions/workflows/ci.yml)\n[![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](./LICENSE)\n![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)\n![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)\n\nTurn a Salesforce Apex debug log into a typed event tree — execution timings, governor limits,\nSOQL/DML counts.\n\n> **Why this library?** It is the same parser that powers the\n> [Apex Log Analyzer](https://github.com/certinia/debug-log-analyzer) VS Code extension —\n> proven on real logs, with zero runtime dependencies and a bundled database of documented\n> Salesforce log events.\n\n## Features\n\n- **171 event types** parsed into typed classes — methods, SOQL, DML, flows, callouts, and more\n- **Hierarchical event tree** with parent/child links and automatic entry/exit matching\n- **Execution timing** per node, self and total, at nanosecond precision\n- **Governor limit tracking** with point-in-time snapshots, per namespace\n- **Per-line limit observations** — each limit line exposed as `{ metric, used, limit }`\n- **SOQL, DML and SOSL counts** aggregated up the tree\n- **Managed package namespace** detection and per-namespace metrics\n- **Zero dependencies**, ESM only\n\n## Install\n\n```bash\n# pnpm\npnpm add @apexdevtools/apex-log-parser\n\n# npm\nnpm install @apexdevtools/apex-log-parser\n\n# yarn\nyarn add @apexdevtools/apex-log-parser\n```\n\n## Quick start\n\nGiven this log:\n\n```\n64.0 APEX_CODE,FINE;APEX_PROFILING,FINEST;CALLOUT,NONE;DB,INFO;NBA,NONE;SYSTEM,NONE;VALIDATION,NONE;VISUALFORCE,NONE;WAVE,NONE;WORKFLOW,NONE\n09:18:22.6 (6508409)|USER_INFO|[EXTERNAL]|005000000000AAA|user@example.com|Greenwich Mean Time|GMTZ\n09:18:22.6 (6574780)|EXECUTION_STARTED\n09:18:22.6 (6600000)|CODE_UNIT_STARTED|[EXTERNAL]|01p4J00000FpS6t|AccountService.refresh()\n09:18:22.6 (7000000)|METHOD_ENTRY|[12]|01p4J00000FpS6t|AccountService.loadAccounts()\n09:18:22.6 (7100000)|SOQL_EXECUTE_BEGIN|[14]|Aggregations:0|SELECT Id, Name FROM Account WHERE Industry = :industry\n09:18:22.6 (9100000)|SOQL_EXECUTE_END|[14]|Rows:50\n09:18:22.6 (9200000)|METHOD_EXIT|[12]|01p4J00000FpS6t|AccountService.loadAccounts()\n09:18:22.6 (9300000)|DML_BEGIN|[20]|Op:Update|Type:Account|Rows:50\n09:18:22.6 (9800000)|DML_END|[20]\n09:18:22.6 (9900000)|CODE_UNIT_FINISHED|AccountService.refresh()\n09:18:22.6 (10100000)|EXECUTION_FINISHED\n```\n\nThis code:\n\n```typescript\nimport { type LogEvent, parse } from '@apexdevtools/apex-log-parser';\n\nfunction printTree(node: LogEvent, depth = 0): void {\n  const indent = '  '.repeat(depth);\n  const ms = (node.duration.total / 1_000_000).toFixed(2);\n  console.log(`${indent}${node.type ?? 'LOG_ROOT'} ${node.text} (${ms}ms)`);\n  for (const child of node.children) {\n    printTree(child, depth + 1);\n  }\n}\n\nconst log = parse(logData);\n\nprintTree(log);\n```\n\nPrints:\n\n```\nLOG_ROOT LOG_ROOT (3.53ms)\n  EXECUTION_STARTED EXECUTION_STARTED (3.53ms)\n    CODE_UNIT_STARTED AccountService.refresh() (3.30ms)\n      METHOD_ENTRY AccountService.loadAccounts() (2.20ms)\n        SOQL_EXECUTE_BEGIN SELECT Id, Name FROM Account WHERE Industry = :industry (2.00ms)\n      DML_BEGIN DML Op:Update Type:Account (0.50ms)\n```\n\nNote the shape. `parse()` returns the root, which is itself a `LogEvent`, so the same walk works\nfrom any node. `METHOD_EXIT`, `SOQL_EXECUTE_END` and `DML_END` are not nodes of their own — each\none closes its matching begin event and sets that event's `exitStamp` and `duration`.\n\nThe root aggregates the whole tree, so totals need no walk:\n\n```typescript\nconsole.log(`SOQL: ${log.soqlCount.total} queries, ${log.soqlRowCount.total} rows`);\nconsole.log(`DML:  ${log.dmlCount.total} statements, ${log.dmlRowCount.total} rows`);\n// SOQL: 1 queries, 50 rows\n// DML:  1 statements, 50 rows\n```\n\nGovernor limits are on the root too. `final` states what the transaction had used when the log\nended, `peak` the highest each metric reached — check `peak` against a ceiling, because counters\nfall mid-log. Each metric states `{ used, limit, percentUsed }`:\n\n```typescript\nconst { final, peak } = log.governorLimits;\n\nconsole.log(`CPU:  ${final.cpuTime.used}/${final.cpuTime.limit}ms`);\nconsole.log(`SOQL: ${peak.soqlQueries.used} at peak (${peak.soqlQueries.percentUsed}%)`);\nconsole.log(`Heap: ${peak.heapSize.used}/${peak.heapSize.limit} bytes`);\n```\n\n## Find the slowest methods\n\n`duration.self` excludes children, so it ranks by time spent in the method itself rather than in\nwhat it called.\n\n```typescript\nimport { type LogEvent, MethodEntryLine, parse } from '@apexdevtools/apex-log-parser';\n\nfunction findSlowest(log: LogEvent, count = 10): { name: string; duration: number }[] {\n  const methods: { name: string; duration: number }[] = [];\n  const stack: LogEvent[] = [...log.children];\n  while (stack.length) {\n    const node = stack.pop();\n    if (!node) {\n      break;\n    }\n    if (node instanceof MethodEntryLine) {\n      methods.push({ name: node.text, duration: node.duration.self });\n    }\n    stack.push(...node.children);\n  }\n  return methods.sort((a, b) => b.duration - a.duration).slice(0, count);\n}\n\nconsole.table(findSlowest(parse(logData)));\n```\n\n## API\n\n`parse(logData: string): ApexLog` — that is the whole entry point. There is no state to reset\nbetween calls, and `ApexLogParser.parse` gives each call its own parser. `ApexLog` is the root\n`LogEvent`, and adds `governorLimits`, `namespaces`, `debugLevels`, `userInfo`, `entryPoint`,\n`truncation`, `logIssues`, `parsingErrors`, `exceptions` and `eventsById`.\n\nThere are two entry points. The root exports runtime values only: `parse`, the `ApexLogParser`\nclass, and the event classes you need for `instanceof` narrowing. Every type, and the\nconst companions that go with them, come from `@apexdevtools/apex-log-parser/types`:\n\n```typescript\nimport { parse } from '@apexdevtools/apex-log-parser';\nimport { LOG_LEVEL, type GovernorLimits } from '@apexdevtools/apex-log-parser/types';\n```\n\nEvery field, event class and type is described in the shipped declarations, so your editor has the\nfull surface.\n\n## Tips\n\n**Capture the log at the right levels.** The parser reports what the log contains. A log captured\nat a low level is missing whole categories of line, and the matching fields stay empty. This is\nthe most common surprise:\n\n| You want | The log needs |\n| --- | --- |\n| `duration` on method nodes | `APEX_CODE` at `FINE` or above, plus `APEX_PROFILING` |\n| `governorLimits` | `APEX_PROFILING` at `FINE` or above, which emits the `CUMULATIVE_LIMIT_USAGE` block |\n| SOQL and DML nodes | `DB` at `INFO` or above |\n| Flow and Process Builder limit lines | `WORKFLOW` at `FINER` |\n\n**All-zero limits mean \"not reported\".** Without a `LIMIT_USAGE_FOR_NS` block, every\n`governorLimits.final` and `governorLimits.peak` metric stays at\n`{ used: 0, limit: 0, percentUsed: null }`. That is not a transaction that used nothing.\n\n**Read totals from the root.** It already aggregates the tree — walking it to count SOQL or DML\nis wasted work.\n\n**Use `eventIndex` as an id.** It is unique, increasing and stable across a parse.\n\n**Two collections, two meanings.** `parsingErrors` holds lines the parser did not understand — a\nparser problem. `logIssues` holds problems in the transaction the log describes, such as a\ntruncated log or an unexpected exit.\n\n## FAQ\n\n### How do I parse a Salesforce Apex debug log in JavaScript or TypeScript?\n\nInstall `@apexdevtools/apex-log-parser` and call `parse()` with the raw log text. It returns a\ntyped tree you can walk, filter and analyse. See [Quick start](#quick-start).\n\n### What Apex debug log event types does it support?\n\n171 event types have a dedicated class, including `METHOD_ENTRY`/`EXIT`,\n`SOQL_EXECUTE_BEGIN`/`END`, `DML_BEGIN`/`END`, `CODE_UNIT_STARTED`/`FINISHED`,\n`FLOW_START_INTERVIEWS_BEGIN`, `CALLOUT_REQUEST`/`RESPONSE`, `EXCEPTION_THROWN` and `FATAL_ERROR`.\nAnything else falls back to a generic line class, so no log line is lost.\n\n### How do I analyse Salesforce governor limits programmatically?\n\nCall `parse()` and read `log.governorLimits` — `final` and `peak`, each stating 13 metrics with\n`used`, `limit` and `percentUsed`, plus `byNamespace` and point-in-time `snapshots`. See [Quick start](#quick-start), and read\n[Tips](#tips) first if every metric comes back zero.\n\n## Requirements\n\n- **Node.js 20 or later.** The package targets ES2022 and runs in any runtime with ES modules —\n  Node, Deno, Bun, and modern browsers. It reads no files and makes no network calls.\n- **ESM only.** There is no CommonJS build, so `require()` does not work.\n- **TypeScript declarations ship with the package.** No `@types` install is needed.\n\n## Stability\n\nThis package is at 0.x. The API is in use by the Apex Log Analyzer and is not expected to churn,\nbut minor versions may still make breaking changes until 1.0.\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup, coding standards, and the PR process.\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md) or the [GitHub Releases](https://github.com/apex-dev-tools/apex-log-parser/releases) for version history.\n\n## License\n\nBSD-3-Clause - [Certinia Inc.](https://certinia.com)\n","readmeFilename":"README.md"}