{"_id":"@dawnlit/outlook-bridge","_rev":"4-d74538af4df22136ed1e0d5a6a55d40e","name":"@dawnlit/outlook-bridge","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"@dawnlit/outlook-bridge","version":"1.0.0","keywords":["outlook","email","automation","powershell","applescript","com"],"author":{"name":"Dawnlit"},"license":"Apache-2.0","_id":"@dawnlit/outlook-bridge@1.0.0","maintainers":[{"name":"wynterlin","email":"yudong9912@gmail.com"}],"homepage":"https://github.com/dawnlit-ai/outlook-bridge#readme","bugs":{"url":"https://github.com/dawnlit-ai/outlook-bridge/issues"},"dist":{"shasum":"19947c422e9fee561d787af71dc5527ceba52c7a","tarball":"https://registry.npmjs.org/@dawnlit/outlook-bridge/-/outlook-bridge-1.0.0.tgz","fileCount":117,"integrity":"sha512-CbRX9j6lObKOEIRreW5k8dOiUZDnGt42E1CG4fyFYqiKMBg70/0hfNkRa+3UypgQMC2gJNSJaGOC9FSc0Z4RcA==","signatures":[{"sig":"MEYCIQCF8C9VYcnpCl0DyTOBY7gL+1h2Ku/uWmUOUgxcZDLj5wIhAKxkxUfXH/Cdk5yJ7AL5JSML7OucoDEldXrUBs69aybs","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dawnlit%2foutlook-bridge@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":505172},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"81129435051273eccece69af1cd246bbe2a4f7c0","scripts":{"test":"npm run build && node --test \"test/*.test.js\"","build":"tsc -p .","prepare":"npm run build"},"_npmUser":{"name":"wynterlin","email":"yudong9912@gmail.com"},"repository":{"url":"git+https://github.com/dawnlit-ai/outlook-bridge.git","type":"git"},"_npmVersion":"11.17.0","description":"Desktop Outlook automation for Node — read, send, reply, file, and template mail by driving the real Outlook client.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"~6.0.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/outlook-bridge_1.0.0_1787560191478_0.6095419234428658","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@dawnlit/outlook-bridge","version":"1.1.0","keywords":["outlook","email","automation","powershell","applescript","com"],"author":{"name":"Dawnlit"},"license":"Apache-2.0","_id":"@dawnlit/outlook-bridge@1.1.0","maintainers":[{"name":"wynterlin","email":"yudong9912@gmail.com"}],"homepage":"https://github.com/dawnlit-ai/outlook-bridge#readme","bugs":{"url":"https://github.com/dawnlit-ai/outlook-bridge/issues"},"dist":{"shasum":"e8c2269ad4bbdf3480bb9ea45cfe6fd4b1f183b7","tarball":"https://registry.npmjs.org/@dawnlit/outlook-bridge/-/outlook-bridge-1.1.0.tgz","fileCount":117,"integrity":"sha512-Q9QzFDCP9cDkpOF1GKQoRO+VCiqeTRoSUutKrqsPFgKMx7U1ZNIQx2CutepmGcYjiYM4JxH0EbBDQw5uLyAlCw==","signatures":[{"sig":"MEQCIHGBZ7IZyrdu5U3BK7et+mSRJ7j+MR9Qot4hHS2zaUt4AiB5I+7YgR/o1EgEx5DodznMfXrXBP0N1YsJJdfovXa2OA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dawnlit%2foutlook-bridge@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":516560},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"4856a5707919a4871af79fc551881a46732c7ef9","scripts":{"test":"npm run build && node --test \"test/*.test.js\"","build":"tsc -p .","prepare":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:739e4902-d47d-4e7c-8f9c-9ab655528db6"}},"repository":{"url":"git+https://github.com/dawnlit-ai/outlook-bridge.git","type":"git"},"_npmVersion":"11.17.0","description":"Desktop Outlook automation for Node — read, send, reply, file, and template mail by driving the real Outlook client.","directories":{},"_nodeVersion":"24.19.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"~6.0.3","@types/node":"^24.0.0"},"_npmOperationalInternal":{"tmp":"tmp/outlook-bridge_1.1.0_1787693559402_0.5193803195726667","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@dawnlit/outlook-bridge","version":"1.1.1","keywords":["outlook","email","automation","powershell","applescript","com"],"author":{"name":"Dawnlit"},"license":"Apache-2.0","_id":"@dawnlit/outlook-bridge@1.1.1","maintainers":[{"name":"wynterlin","email":"yudong9912@gmail.com"}],"homepage":"https://github.com/dawnlit-ai/outlook-bridge#readme","bugs":{"url":"https://github.com/dawnlit-ai/outlook-bridge/issues"},"dist":{"shasum":"8a8c50ffb7a66fb4ae21b4695ff54a9a64bbb944","tarball":"https://registry.npmjs.org/@dawnlit/outlook-bridge/-/outlook-bridge-1.1.1.tgz","fileCount":117,"integrity":"sha512-mRu9goOdQtH1do8iKKoObwvtgIgtbhus/DLk59HKA2KoMuzNVzHx+SJD6s4eAF7rkp1gbgfR08pbOAPBxhs3hQ==","signatures":[{"sig":"MEUCIGESuXSYWi2Pa/+hrST7BI1khXpun8dtLt5MfnNxvrjrAiEA6gvjy+qzBvssm3gdAtE265D32G/sshU5q1nEoLQ9lTQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dawnlit%2foutlook-bridge@1.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":525670},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"166b0c3407c03402dcea04bcac0b607d5ef0b620","scripts":{"test":"npm run build && node --test \"test/*.test.js\"","build":"tsc -p .","prepare":"npm run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:739e4902-d47d-4e7c-8f9c-9ab655528db6"}},"repository":{"url":"git+https://github.com/dawnlit-ai/outlook-bridge.git","type":"git"},"_npmVersion":"11.19.0","description":"Desktop Outlook automation for Node — read, send, reply, file, and template mail by driving the real Outlook client.","directories":{},"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"~6.0.3","@types/node":"^24.13.3"},"_npmOperationalInternal":{"tmp":"tmp/outlook-bridge_1.1.1_1788766916394_0.8809181129129364","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"_id":"@dawnlit/outlook-bridge@2.0.0","bugs":{"url":"https://github.com/dawnlit-ai/outlook-bridge/issues"},"dist":{"shasum":"86c139f533c444d18bfb4703e74f6e5df3a6bbf0","tarball":"https://registry.npmjs.org/@dawnlit/outlook-bridge/-/outlook-bridge-2.0.0.tgz","fileCount":132,"integrity":"sha512-PwjspF4ohbsYcMf+sl26wgSErnuFI8IJAfqE6CVKapYvvlm//4FzgHhyUOPmlVU/4JjfBhGTHD2ihXVdjQ2plQ==","signatures":[{"sig":"MEUCIQCAIdgB1g7hkuEDpcZKjWTJvG37hhxeU6Qh1/DTysy+zwIgM6KMnPDEWiE5kWDPT/K9fIKGKVOdMEtKj/5bEA1rvXw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD8KMNk3OEKm284oMYMCGzn+MPLlYHLjUPugWm1ml+vdgIhANt/w+oOqq/hn1TUy4fvtIYnprobAZJwxZMcRR+Lg893"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dawnlit%2foutlook-bridge@2.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":945807},"main":"dist/index.js","name":"@dawnlit/outlook-bridge","types":"dist/index.d.ts","author":{"name":"Dawnlit"},"engines":{"node":">=24"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"9c46065b0941e524e09eda4a25a089cdaf513f9d","license":"Apache-2.0","scripts":{"test":"npm run build && node --test \"test/*.test.js\"","build":"npm run clean && tsc -p .","clean":"node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"","prepare":"npm run build"},"version":"2.0.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:739e4902-d47d-4e7c-8f9c-9ab655528db6"}},"homepage":"https://github.com/dawnlit-ai/outlook-bridge#readme","keywords":["outlook","email","automation","powershell","applescript","com"],"repository":{"url":"git+https://github.com/dawnlit-ai/outlook-bridge.git","type":"git"},"_npmVersion":"11.19.0","description":"Desktop Outlook automation for Node — read, search, send, reply, file, and template mail by driving the real Outlook client on Windows and macOS.","directories":{},"maintainers":[{"name":"wynterlin","email":"yudong9912@gmail.com"}],"_nodeVersion":"24.20.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"~6.0.3","@types/node":"^24.13.3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/outlook-bridge_2.0.0_1790146273789_0.34292987703571787"}}},"time":{"created":"2026-08-24T08:29:51.337Z","modified":"2026-09-23T06:51:14.242Z","1.0.0":"2026-08-24T08:29:51.641Z","1.1.0":"2026-08-25T21:32:39.550Z","1.1.1":"2026-09-07T07:41:56.533Z","2.0.0":"2026-09-23T06:51:13.867Z"},"bugs":{"url":"https://github.com/dawnlit-ai/outlook-bridge/issues"},"author":{"name":"Dawnlit"},"license":"Apache-2.0","homepage":"https://github.com/dawnlit-ai/outlook-bridge#readme","keywords":["outlook","email","automation","powershell","applescript","com"],"repository":{"url":"git+https://github.com/dawnlit-ai/outlook-bridge.git","type":"git"},"description":"Desktop Outlook automation for Node — read, search, send, reply, file, and template mail by driving the real Outlook client on Windows and macOS.","maintainers":[{"name":"wynterlin","email":"yudong9912@gmail.com"}],"readme":"# @dawnlit/outlook-bridge\n\nDrive a real, locally installed Outlook client from Node — read and search mail, send and reply, manage drafts, save\nattachments, work with signatures and template emails, file and delete messages. No Graph API, no app registration, no\ncloud permissions: this automates the desktop client itself, the way a person would.\n\n- **Windows** — PowerShell and Outlook's COM object model.\n- **macOS** — AppleScript. Requires **legacy** Outlook for Mac: New Outlook implements only a slice of the AppleScript\n  dictionary (accounts don't enumerate, the inbox reports no messages), so every call fails with `ACCOUNT_NOT_FOUND`\n  there rather than quietly doing the wrong thing.\n- **Anywhere else** — `capabilities()` reports nothing supported and every call rejects with `UNSUPPORTED_PLATFORM`.\n\n## Install\n\n```bash\nnpm install @dawnlit/outlook-bridge\n```\n\nRequires Node 24+ and a real Outlook on the machine running it — this is desktop automation, not a hosted API client.\n\n## Usage\n\n```ts\nimport { getOutlookAccounts, readInboxEmails, readEmailBody, replyOutlookEmail } from '@dawnlit/outlook-bridge';\n\nconst [account] = await getOutlookAccounts();\n\nconst recent = await readInboxEmails(account, { daysBack: 7, limit: 20 });\n\n// A listing row can be passed straight back in as the email to act on.\nconst email = recent[0];\nconst { body } = await readEmailBody(email);\n\nawait replyOutlookEmail({\n    emailAccount: account,\n    entryId: email.entryId,\n    storeId: email.storeId,\n    htmlBody: '<p>Thanks — received.</p>',\n    openDraftWindow: false, // file the reply in Drafts without opening a window\n});\n```\n\nEvery operation takes its required arguments positionally and everything optional as one options object, with the\nsame defaults and the same validation on both platforms.\n\n### Operations\n\n| Area                   | Operations                                                                                                                                                                                                                                                                                                                                                                                       |\n|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Accounts               | `getOutlookAccounts`                                                                                                                                                                                                                                                                                                                                                                             |\n| Reading                | `readInboxEmails` (the Inbox root, or any folder by name or path), `searchInboxByFilter` (walks the whole Inbox tree by subject glob or pattern, date window, attachments, folders), `readEmailBody` (the sender's own text, split from the quoted thread), `readSelectedEmail`, `openOutlookEmail`, `locateEmail` (finds an email again by subject, sender and time once its id has gone stale) |\n| Folders                | `listInboxFolders`, `moveOutlookEmails` (creates a missing destination chain on request)                                                                                                                                                                                                                                                                                                         |\n| Composing              | `sendOutlookEmail` (to/cc/bcc, several attachments, a named signature, send or draft), `replyOutlookEmail` (reply or reply-all, from HTML or a saved template)                                                                                                                                                                                                                                   |\n| Drafts                 | `listOutlookDrafts`, `sendDrafts` (a chosen subset), `sendAllDrafts`, `deleteOutlookDrafts`                                                                                                                                                                                                                                                                                                      |\n| Attachments            | `saveEmailAttachment`, `saveEmailAttachments`                                                                                                                                                                                                                                                                                                                                                    |\n| Cleanup                | `deleteOutlookEmails` (refuses received and sent mail unless allowed; dry-run first), `purgeDeletedItems`                                                                                                                                                                                                                                                                                        |\n| Bounces                | `cleanUndeliverableEmails`, `readBounceReport` (which sent messages bounced, and for which recipients), `collectBouncedRecipients`, `readSentRecipientGroups`                                                                                                                                                                                                                                    |\n| Signatures & templates | `listOutlookSignatures`, `readOutlookSignatureHtml`, `readTemplateEmails`, `saveTemplateEmail`, `editEmailTemplate`                                                                                                                                                                                                                                                                              |\n\nEach is documented where it is declared, in `OutlookBridge` (see `dist/types.d.ts`), with every option and default.\n\nA few pure helpers need no Outlook: `threadSubject` (a subject with every stacked reply and forward prefix stripped, in\nany of the languages `RE:`, `AW:` or `回复:` come in — the subject a whole thread shares), `hasReplyPrefix`,\n`splitQuotedOriginal` (the sender's new text apart from the quoted thread) and `mailFolderRef`.\n\n### Identifying an email\n\nListings return an `entryId` and a `storeId`. Operations on one email accept an `EmailRef`: the entry id alone, or any\nobject carrying `{ entryId, storeId? }` — so the row itself can be passed back. Passing the row is also the reliable way\nto keep a `storeId` with its own `entryId`; the store id is what lets an email resolve in a mailbox other than the\ndefault one.\n\n**Ids are not portable between platforms.** Windows returns MAPI EntryIDs; macOS returns Outlook for macOS small integer\nmessage ids, and has no store id (it reports `''` and ignores one passed in). Each platform rejects the other's ids with\n`INVALID_REQUEST`. **Moving an email rewrites its id** on both, so ids saved before a move are stale afterward. Keep the\nsubject, sender and received time beside a saved id, and `locateEmail` finds the email again from them wherever it has\nmoved under the Inbox, on either platform.\n\nTimestamps are local time as `yyyy-MM-dd HH:mm`, which sorts correctly as a string.\n\n### Templates\n\nA template email is an ordinary email saved in a mailbox folder (default `Templates`) and edited in Outlook. One template\ncan hold several variants of a reply between `[[SECTION]] ... [[/SECTION]]` markers around a shared greeting and\nclosing, with `{{PLACEHOLDER}}` tokens:\n\n```ts\nawait replyOutlookEmail({\n    emailAccount: account,\n    entryId: email.entryId,\n    storeId: email.storeId,\n    templateSubject: 'Standard reply',\n    templateSection: 'ACCEPT',\n    templatePlaceholders: { NOTE: 'We will confirm by Friday.' },\n    signatureName: 'Work', // fills {{SIGNATURE}}\n});\n```\n\nThe template, the section, the placeholders and the signature are all resolved inside the package, so a large\nWord-generated template never has to pass through the caller. Composition refuses rather than guesses: a missing section,\nan unknown placeholder, or a marker left unresolved fails with `INVALID_REQUEST` before anything is created.\n\nThe same toolkit works on any HTML string: `composeTemplateBody`, `findTemplateMarkers`, and for `{Token}`-style fills,\n`replaceToken`, `removeTokenLine` (removes a token together with its table row or paragraph), `findTokens` and\n`findUnfilledTokens`.\n\n## Configuration\n\nEvery call generates a script and runs it under an interpreter. The settings are how long a run may take, how much it may\nprint, how to call it off, and what the script said:\n\n```ts\nimport { createOutlookBridge } from '@dawnlit/outlook-bridge';\n\nconst outlook = createOutlookBridge({\n    timeoutMs: 120_000,               // ceiling on every run (default: a budget sized for each operation)\n    maxBufferBytes: 32 * 1024 * 1024, // output cap; searches returning bodies push against it (default 8 MiB)\n    tempDir: '/var/tmp/outlook',      // generated scripts, and attachments saved without a destination\n    debug: event => log(event.script),// every generated script, its duration, and any error\n});\n```\n\n- **Timeouts.** Unless `timeoutMs` is set, each run gets a budget sized for its work — a minute for a lookup, two for\n  composing or reading a folder, five for a mailbox walk or a batch, ten for purging. `timeoutMs` replaces all of them;\n  `0` disables timeouts; `null` goes back to the budgets. `editEmailTemplate` waits on a person and is never timed —\n  cancel it with a signal.\n- **Instances.** A bridge's settings apply to its own calls only, even when several bridges run at once.\n  `outlook.withOptions({ ... })` derives a bridge with some settings changed — which is how a single call gets its own\n  budget or cancellation:\n\n  ```ts\n  const controller = new AbortController();\n  cancelButton.onclick = () => controller.abort();\n  await outlook.withOptions({ signal: controller.signal }).searchInboxByFilter(account, { daysBack: 365 });\n  // → rejects with ABORTED, interpreter killed\n  ```\n\n- **Process-wide.** The exported functions run under process-wide settings that `configure()` changes. That is the\n  simpler choice for a program that owns its process; prefer `createOutlookBridge` in anything sharing one.\n- **Debugging.** `OUTLOOK_BRIDGE_DEBUG=1` logs every script to stderr without a code change.\n\nCapability discovery answers for the machine you are on: `capabilities()` returns a map of every operation to\n`true`/`false`, and `supports('searchInboxByFilter')` asks about one.\n\n## Errors\n\nEvery deliberate failure is an `OutlookError` with a stable `code`. **The codes are the API; the messages are not** —\nbranch on `code`, never on message text.\n\n```ts\nimport { OutlookError } from '@dawnlit/outlook-bridge';\n\ntry {\n    await outlook.readInboxEmails(account, { folder: 'Invoices\\\\2026' });\n} catch (error) {\n    if (!(error instanceof OutlookError)) throw error; // a bug\n    switch (error.code) {\n        case 'ACCOUNT_NOT_FOUND': return askForAccount(error.account);\n        case 'NOT_FOUND':         return report(`${error.kind} missing: ${error.message}`);\n        case 'OUTPUT_TOO_LARGE':  return retryWithNarrowerWindow();\n        case 'SCRIPT_FAILED':     return logFailure(error.script, error.line, error.stderr);\n    }\n}\n```\n\n| code                   | class                      | meaning                                                                                                                                                        |\n|------------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `UNSUPPORTED_PLATFORM` | `UnsupportedPlatformError` | No Outlook automation exists on this OS.                                                                                                                       |\n| `NOT_IMPLEMENTED`      | `NotImplementedError`      | The platform could do this, but this corner isn't written (a folder root macOS has no term for).                                                               |\n| `ACCOUNT_NOT_FOUND`    | `AccountNotFoundError`     | No mailbox in the profile matches the address. Carries `account`.                                                                                              |\n| `NOT_FOUND`            | `NotFoundError`            | A `folder`, `email`, `attachment`, `template`, `signature` or `file` didn't resolve. Carries `kind`.                                                           |\n| `INVALID_REQUEST`      | `InvalidRequestError`      | The arguments can't produce a call — a wrong type, a missing value, a template edited into an unusable state, or a mailbox that can be read but not sent from. |\n| `SCRIPT_FAILED`        | `ScriptError`              | The script ran and failed. Carries `script`, `line`, `stderr`, `runner`, `durationMs`.                                                                         |\n| `OUTPUT_TOO_LARGE`     | `OutputTooLargeError`      | The script printed more than `maxBufferBytes`.                                                                                                                 |\n| `TIMEOUT`              | `TimeoutError`             | The run exceeded its time budget and was killed. Carries `timeoutMs`.                                                                                          |\n| `ABORTED`              | `AbortedError`             | The caller's `AbortSignal` fired.                                                                                                                              |\n\nBatch operations (moving, deleting, sending drafts, cleaning bounces) don't throw for one bad item: they report each\nfailure in `failed` beside the items that worked.\n\n## Security\n\nCaller text ends up inside generated scripts, so the package treats every argument as untrusted:\n\n- Arguments are checked for type at run time — a count must be a finite number, a flag a boolean — before any script\n  is generated, whatever TypeScript believed at compile time.\n- On Windows, caller text only ever appears in single-quoted PowerShell literals, with every quote character PowerShell\n  accepts (including the typographic `‘ ’ ‚ ‛`) escaped. Text that has to appear in a message is referenced through a\n  variable, never interpolated into a double-quoted string where `$(...)` would run. Scripts run from UTF-8 files with a\n  byte-order mark, so non-ASCII text arrives intact.\n- Attachment names come from the sender, so a saved file's name is sanitized — no path separators, reserved device\n  names or characters the file system rejects — and never overwrites an existing file.\n\n## Module format\n\nPublished as CommonJS; ESM consumers can use named imports normally. There is deliberately no dual build: the package\nidentifies its errors with `instanceof`, and a dual-format package can load two copies of itself into one process.\n\n## Development\n\n```bash\nnpm run build   # tsc → dist/\nnpm test        # build, then node:test\n```\n\nThe tests need no Outlook. They cover every operation's validation and defaults against a fake backend, the pure\nhelpers, the error taxonomy, and the generated scripts themselves:\n\n- **On Windows**, every PowerShell script every operation generates is put through PowerShell's own parser, with\n  arguments built to break out of a badly escaped literal. The test fails on a syntax error, and on any caller text\n  inside a double-quoted string.\n- **On a Mac with Outlook installed**, every AppleScript is compiled with `osacompile`, which resolves dictionary terms\n  without opening a session. Elsewhere, those tests skip; two guards that need no Outlook — no assignment to a reserved\n  AppleScript word, no record field read through a nested accessor — run everywhere.\n\nWhat no test covers is the automation itself: that a move really filed the mail, or a reply threaded correctly, is\nverified against a live mailbox.\n\n## License\n\nApache-2.0 © Dawnlit\n","readmeFilename":"README.md"}