@dawnlit/outlook-bridge 1.1.1 → 2.1.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.
Files changed (142) hide show
  1. package/README.md +152 -183
  2. package/dist/backend.d.ts +151 -0
  3. package/dist/backend.js +3 -0
  4. package/dist/backend.js.map +1 -0
  5. package/dist/bridge.d.ts +56 -0
  6. package/dist/bridge.js +507 -0
  7. package/dist/bridge.js.map +1 -0
  8. package/dist/errors.d.ts +79 -43
  9. package/dist/errors.js +93 -52
  10. package/dist/errors.js.map +1 -1
  11. package/dist/index.d.ts +10 -10
  12. package/dist/index.js +25 -52
  13. package/dist/index.js.map +1 -1
  14. package/dist/mac/accounts.d.ts +7 -2
  15. package/dist/mac/accounts.js +23 -6
  16. package/dist/mac/accounts.js.map +1 -1
  17. package/dist/mac/attachments.d.ts +5 -25
  18. package/dist/mac/attachments.js +40 -99
  19. package/dist/mac/attachments.js.map +1 -1
  20. package/dist/mac/bounces.d.ts +12 -27
  21. package/dist/mac/bounces.js +96 -117
  22. package/dist/mac/bounces.js.map +1 -1
  23. package/dist/mac/cleanup.d.ts +11 -25
  24. package/dist/mac/cleanup.js +44 -107
  25. package/dist/mac/cleanup.js.map +1 -1
  26. package/dist/mac/drafts.d.ts +15 -34
  27. package/dist/mac/drafts.js +113 -186
  28. package/dist/mac/drafts.js.map +1 -1
  29. package/dist/mac/folders.d.ts +12 -21
  30. package/dist/mac/folders.js +44 -59
  31. package/dist/mac/folders.js.map +1 -1
  32. package/dist/mac/index.d.ts +2 -22
  33. package/dist/mac/index.js +19 -81
  34. package/dist/mac/index.js.map +1 -1
  35. package/dist/mac/profile.d.ts +13 -0
  36. package/dist/mac/profile.js +149 -0
  37. package/dist/mac/profile.js.map +1 -0
  38. package/dist/mac/read.d.ts +21 -37
  39. package/dist/mac/read.js +198 -216
  40. package/dist/mac/read.js.map +1 -1
  41. package/dist/mac/run.d.ts +51 -38
  42. package/dist/mac/run.js +138 -103
  43. package/dist/mac/run.js.map +1 -1
  44. package/dist/mac/scripts.d.ts +90 -91
  45. package/dist/mac/scripts.js +167 -126
  46. package/dist/mac/scripts.js.map +1 -1
  47. package/dist/mac/send.d.ts +10 -20
  48. package/dist/mac/send.js +99 -89
  49. package/dist/mac/send.js.map +1 -1
  50. package/dist/mac/signatures.d.ts +2 -2
  51. package/dist/mac/signatures.js +9 -11
  52. package/dist/mac/signatures.js.map +1 -1
  53. package/dist/mac/templates.d.ts +14 -26
  54. package/dist/mac/templates.js +79 -120
  55. package/dist/mac/templates.js.map +1 -1
  56. package/dist/mail.d.ts +80 -46
  57. package/dist/mail.js +179 -73
  58. package/dist/mail.js.map +1 -1
  59. package/dist/runtime.d.ts +76 -43
  60. package/dist/runtime.js +103 -48
  61. package/dist/runtime.js.map +1 -1
  62. package/dist/shared/args.d.ts +48 -0
  63. package/dist/shared/args.js +216 -0
  64. package/dist/shared/args.js.map +1 -0
  65. package/dist/shared/attachmentMatch.d.ts +26 -20
  66. package/dist/shared/attachmentMatch.js +60 -23
  67. package/dist/shared/attachmentMatch.js.map +1 -1
  68. package/dist/shared/bounceReport.d.ts +11 -0
  69. package/dist/shared/bounceReport.js +45 -0
  70. package/dist/shared/bounceReport.js.map +1 -0
  71. package/dist/shared/bounceRules.d.ts +38 -10
  72. package/dist/shared/bounceRules.js +50 -32
  73. package/dist/shared/bounceRules.js.map +1 -1
  74. package/dist/shared/exec.d.ts +21 -0
  75. package/dist/shared/exec.js +47 -0
  76. package/dist/shared/exec.js.map +1 -0
  77. package/dist/shared/json.d.ts +17 -6
  78. package/dist/shared/json.js +35 -24
  79. package/dist/shared/json.js.map +1 -1
  80. package/dist/shared/locate.d.ts +31 -0
  81. package/dist/shared/locate.js +128 -0
  82. package/dist/shared/locate.js.map +1 -0
  83. package/dist/shared/replyBody.d.ts +31 -36
  84. package/dist/shared/replyBody.js +83 -72
  85. package/dist/shared/replyBody.js.map +1 -1
  86. package/dist/shared/templateLimits.d.ts +14 -0
  87. package/dist/shared/templateLimits.js +21 -0
  88. package/dist/shared/templateLimits.js.map +1 -0
  89. package/dist/templateBody.d.ts +69 -0
  90. package/dist/{outlookTemplateSections.js → templateBody.js} +80 -73
  91. package/dist/templateBody.js.map +1 -0
  92. package/dist/types.d.ts +381 -168
  93. package/dist/types.js +8 -9
  94. package/dist/types.js.map +1 -1
  95. package/dist/windows/accounts.d.ts +7 -12
  96. package/dist/windows/accounts.js +19 -34
  97. package/dist/windows/accounts.js.map +1 -1
  98. package/dist/windows/attachments.d.ts +9 -24
  99. package/dist/windows/attachments.js +94 -119
  100. package/dist/windows/attachments.js.map +1 -1
  101. package/dist/windows/bounces.d.ts +13 -26
  102. package/dist/windows/bounces.js +168 -200
  103. package/dist/windows/bounces.js.map +1 -1
  104. package/dist/windows/cleanup.d.ts +23 -23
  105. package/dist/windows/cleanup.js +99 -113
  106. package/dist/windows/cleanup.js.map +1 -1
  107. package/dist/windows/drafts.d.ts +16 -35
  108. package/dist/windows/drafts.js +156 -253
  109. package/dist/windows/drafts.js.map +1 -1
  110. package/dist/windows/folders.d.ts +8 -13
  111. package/dist/windows/folders.js +44 -52
  112. package/dist/windows/folders.js.map +1 -1
  113. package/dist/windows/index.d.ts +2 -27
  114. package/dist/windows/index.js +11 -66
  115. package/dist/windows/index.js.map +1 -1
  116. package/dist/windows/read.d.ts +24 -60
  117. package/dist/windows/read.js +265 -306
  118. package/dist/windows/read.js.map +1 -1
  119. package/dist/windows/run.d.ts +38 -40
  120. package/dist/windows/run.js +151 -112
  121. package/dist/windows/run.js.map +1 -1
  122. package/dist/windows/scripts.d.ts +65 -55
  123. package/dist/windows/scripts.js +109 -85
  124. package/dist/windows/scripts.js.map +1 -1
  125. package/dist/windows/send.d.ts +9 -9
  126. package/dist/windows/send.js +76 -88
  127. package/dist/windows/send.js.map +1 -1
  128. package/dist/windows/signatures.d.ts +4 -10
  129. package/dist/windows/signatures.js +30 -37
  130. package/dist/windows/signatures.js.map +1 -1
  131. package/dist/windows/templates.d.ts +12 -18
  132. package/dist/windows/templates.js +117 -150
  133. package/dist/windows/templates.js.map +1 -1
  134. package/package.json +5 -4
  135. package/dist/OutlookService.d.ts +0 -43
  136. package/dist/OutlookService.js +0 -137
  137. package/dist/OutlookService.js.map +0 -1
  138. package/dist/outlookTemplateSections.d.ts +0 -62
  139. package/dist/outlookTemplateSections.js.map +0 -1
  140. package/dist/shared/capabilities.d.ts +0 -3
  141. package/dist/shared/capabilities.js +0 -9
  142. package/dist/shared/capabilities.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/mac/read.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../src/mac/read.ts"],"names":[],"mappings":"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","sourcesContent":["// Reading mail on macOS: one folder, one item, a whole Inbox tree, or whatever\n// is selected in the running Outlook.\n//\n// Every reader is two passes. Pass 1 indexes a folder with bulk property reads\n// (one Apple event each); pass 2 fetches the expensive fields — body,\n// attachments, sender — only for the messages that survived. Reading\n// per-message in a loop costs an event per property and is unusably slow on a\n// real mailbox, which is the whole reason for the shape.\nimport {\n AS_LIST_SEP,\n asIdList,\n asInt,\n asRow,\n asString,\n field,\n runOsaScript,\n splitFields,\n splitList,\n splitPositionalList,\n splitRecords,\n summaryFields,\n} from './run';\nimport { readProfileAccounts } from './profile';\nimport {\n accountLookupSnippet,\n dateProperty,\n firstRecipientSnippet,\n folderChainSnippet,\n macFolderPath,\n macMessageId,\n mailScopeSnippet,\n MessageDetail,\n messageDetailFields,\n messageDetailSnippet,\n messageLookupSnippet,\n resolveMacAccount,\n rootFolderSnippet,\n senderSnippet,\n} from './scripts';\nimport { failureTag, NotFoundError } from '../errors';\nimport { folderLeafName, isOutgoingRoot, REPLY_PREFIX, subjectGlobSource } from '../mail';\nimport type { RawEmail, ReadInboxRequest, SearchRequest } from '../backend';\nimport type { EmailLocator, InboxEmail, InboxSearchMatch, SelectedEmail } from '../types';\n\n/**\n * Recent mail from the Inbox root or one folder, newest first. Entry ids here\n * are Outlook for Mac's integer message ids, not Windows EntryIDs.\n */\nexport async function readInboxEmails(request: ReadInboxRequest): Promise<InboxEmail[]> {\n const acct = await resolveMacAccount(request.account);\n const folderPath = macFolderPath(request.account, request.folder.rootLabel, request.folder.segments);\n const outgoing = isOutgoingRoot(request.folder.rootId);\n\n // Pass 1 — index the folder. Its order isn't documented, so it is sorted here.\n const index = (await runOsaScript(`tell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${mailScopeSnippet(acct, request.folder, request.folderLabel)}\n set cutoff to (current date) - (${asInt(request.daysBack)} * days)\n set idList to id of every message of scopeFolder\n try\n set timeList to ${dateProperty(request.folder.rootId)} of every message of scopeFolder\n on error\n set timeList to {}\n end try\n set hasTimes to ((count of timeList) is (count of idList))\n set out to \"\"\n repeat with i from 1 to (count of idList)\n set d to missing value\n if hasTimes then set d to item i of timeList\n -- An item with no timestamp of its own (an unsent draft filed into a\n -- mail folder) is skipped, as the Windows date filter skips it.\n if d is not missing value and d is greater than or equal to cutoff then\n set out to out & (item i of idList as string) & tab & my isoDate(d) & linefeed\n end if\n end repeat\n return out\nend tell`, 'standard'))\n .split('\\n')\n .map(line => line.trim())\n .filter(Boolean)\n .map(line => {\n const [id, receivedTime] = line.split('\\t');\n return { id, receivedTime: receivedTime || '' };\n });\n // 'yyyy-MM-dd HH:mm' sorts correctly as a string.\n index.sort((a, b) => b.receivedTime.localeCompare(a.receivedTime));\n const chosen = index.slice(0, request.limit);\n if (chosen.length === 0) return [];\n\n // Pass 2 — the expensive reads, only for the messages kept.\n const preview = request.previewChars > 0\n ? ` set bodyText to \"\"\n try\n set bodyText to (plain text content of theMsg) as string\n end try\n if (length of bodyText) > ${asInt(request.previewChars)} then set bodyText to text 1 thru ${asInt(request.previewChars)} of bodyText`\n : ' set bodyText to \"\"';\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n set out to \"\"\n repeat with theId in ${asIdList(chosen.map(c => c.id))}\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is not missing value then\n set subj to \"\"\n try\n set subj to (subject of theMsg) as string\n end try\n${outgoing ? firstRecipientSnippet(' ') : senderSnippet(' ')}\n${preview}\n set attNames to {}\n try\n set attNames to name of every attachment of theMsg\n end try\n set out to out & ${asRow(['(id of theMsg as string)', 'subj', 'sndName', 'sndAddr', 'bodyText', 'my sanitizePositionalList(attNames)'])}\n end if\n end repeat\n return out\nend tell`, 'standard');\n\n const receivedById = new Map(chosen.map(c => [c.id, c.receivedTime]));\n return splitRecords(raw).map(record => {\n const parts = splitFields(record);\n const id = field(parts, 0);\n const attachmentNames = splitPositionalList(field(parts, 5));\n return {\n entryId: id,\n storeId: '',\n subject: field(parts, 1).trim(),\n senderName: field(parts, 2),\n senderEmail: field(parts, 3),\n receivedTime: receivedById.get(id) || '',\n bodyPreview: field(parts, 4),\n attachmentNames,\n attachmentCount: attachmentNames.length,\n folderPath,\n };\n });\n}\n\n/**\n * One email's full plain-text body. `storeId` has no macOS meaning: `message id\n * N` resolves against the application, wherever the message sits.\n */\nexport async function readEmailBody(email: EmailLocator): Promise<RawEmail> {\n const id = macMessageId(email.entryId);\n const parts = summaryFields(await runOsaScript(`tell application \"Microsoft Outlook\"\n${messageLookupSnippet(id)}\n${messageDetailSnippet(true)}\n return ${asRow(messageDetailFields(true))}\nend tell`, 'quick'));\n return {\n entryId: field(parts, MessageDetail.id) || id,\n subject: field(parts, MessageDetail.subject).trim(),\n senderName: field(parts, MessageDetail.senderName),\n senderEmail: field(parts, MessageDetail.senderEmail),\n receivedTime: field(parts, MessageDetail.receivedTime),\n body: field(parts, MessageDetail.body),\n attachmentNames: splitPositionalList(field(parts, MessageDetail.attachmentNames)),\n };\n}\n\n/**\n * Walk every folder under the Inbox for the mail matching the request.\n *\n * The filtering happens here rather than in Outlook: there is no AppleScript\n * counterpart to COM's server-side `Items.Restrict`, so each folder is indexed in\n * bulk reads and the subject and date tests run on the index. The results match\n * Windows; the cost doesn't, and a wide window over a big tree is heavier here.\n */\nexport async function searchInboxByFilter(request: SearchRequest): Promise<InboxSearchMatch[]> {\n const acct = await resolveMacAccount(request.account);\n // AppleScript reaches a child folder by name, so a path entry narrows to its leaf.\n const asNameList = (list: readonly string[]) => `{${list.map(folderLeafName).filter(Boolean).map(asString).join(', ')}}`;\n const rootInScope = request.includeFolders.length === 0 ? 'true' : 'false';\n // Sent, Drafts, Deleted and Junk hang UNDER the Inbox on an IMAP profile, so\n // their ids are collected first and the walk never descends into them — by\n // the profile's own id where it records one, through the account otherwise.\n const skipIds = ['sent items', 'deleted items', 'drafts', 'junk mail']\n .map(term => {\n const id = acct.folderIds?.[term];\n return id !== undefined\n ? ` set end of skipIds to ${id}`\n : ` try\n set end of skipIds to (id of (${term} of targetAcct))\n end try`;\n })\n .join('\\n');\n\n // Pass 1 — index every folder under the Inbox: path, id, subject, received.\n const indexed = splitRecords(await runOsaScript(`on scanFolder(theFolder, prefix, cutoff, skipIds, skipNames, onlyNames, inScope)\n set out to \"\"\n set idList to {}\n set subjList to {}\n set timeList to {}\n -- A folder the walk only passes through is never read: the bulk reads are\n -- the expensive part.\n if inScope then\n tell application \"Microsoft Outlook\"\n set idList to id of every message of theFolder\n set subjList to subject of every message of theFolder\n try\n set timeList to time received of every message of theFolder\n on error\n set timeList to {}\n end try\n end tell\n end if\n tell application \"Microsoft Outlook\"\n set subs to mail folders of theFolder\n end tell\n set hasTimes to ((count of timeList) is (count of idList))\n repeat with i from 1 to (count of idList)\n set d to missing value\n if hasTimes then set d to item i of timeList\n -- An item with no readable receive time is kept whatever the window\n -- says; dropping it would make a folder of them look empty.\n if d is missing value or d is not less than cutoff then\n set out to out & ${asRow(['prefix', '(item i of idList as string)', '(item i of subjList)', 'my isoDate(d)'])}\n end if\n end repeat\n repeat with f in subs\n set skipThis to false\n try\n if skipIds contains (id of f) then set skipThis to true\n end try\n try\n if skipNames contains ((name of f) as string) then set skipThis to true\n end try\n if not skipThis then\n set childName to \"\"\n try\n set childName to (name of f) as string\n end try\n set childScope to (count of onlyNames) is 0\n try\n if onlyNames contains childName then set childScope to true\n end try\n set out to out & my scanFolder(f, prefix & ${AS_LIST_SEP} & childName, cutoff, skipIds, skipNames, onlyNames, childScope)\n end if\n end repeat\n return out\nend scanFolder\n\ntell application \"Microsoft Outlook\"\n${accountLookupSnippet(acct)}\n${rootFolderSnippet(acct, 'inbox', 'rootInbox')}\n set rootName to (name of rootInbox) as string\n set skipIds to {}\n${skipIds}\n set skipNames to ${asNameList(request.excludeFolders)}\n set onlyNames to ${asNameList(request.includeFolders)}\nend tell\nset cutoff to (current date) - (${asInt(request.daysBack)} * days)\nreturn my scanFolder(rootInbox, rootName, cutoff, skipIds, skipNames, onlyNames, ${rootInScope})`, 'scan'));\n\n const subjectFiltered = !!(request.subjectLike || request.subjectPattern || request.excludeReplies);\n const likeRe = request.subjectLike ? new RegExp(subjectGlobSource(request.subjectLike), 'i') : null;\n // PowerShell's -match is case-insensitive, so this test is too, whatever the\n // caller's flags. Only u and v are kept: they decide how the source parses,\n // and without u, /\\p{L}/u would match the literal text \"p{L}\". Keeping g or y\n // would carry lastIndex from one subject to the next.\n const patternRe = request.subjectPattern\n ? new RegExp(request.subjectPattern.source, 'i' + request.subjectPattern.flags.replace(/[^uv]/g, ''))\n : null;\n const candidates = indexed\n .map(record => {\n const parts = splitFields(record);\n const segments = splitList(field(parts, 0));\n return {\n folderPath: macFolderPath(request.account, segments[0] || 'Inbox', segments.slice(1)),\n id: field(parts, 1),\n subject: field(parts, 2).trim(),\n receivedTime: field(parts, 3),\n };\n })\n .filter(candidate => {\n if (subjectFiltered && !candidate.subject) return false;\n if (likeRe && !likeRe.test(candidate.subject)) return false;\n if (patternRe && !patternRe.test(candidate.subject)) return false;\n if (request.excludeReplies && REPLY_PREFIX.test(candidate.subject)) return false;\n return true;\n });\n if (candidates.length === 0) return [];\n\n // Pass 2 — senders, attachment names and (when asked) bodies, for the survivors only.\n const body = request.includeBody\n ? ` set bodyText to \"\"\n try\n set bodyText to (plain text content of theMsg) as string\n end try`\n : ' set bodyText to \"\"';\n const raw = await runOsaScript(`tell application \"Microsoft Outlook\"\n set out to \"\"\n repeat with theId in ${asIdList(candidates.map(c => c.id))}\n set theMsg to missing value\n try\n set theMsg to message id theId\n end try\n if theMsg is not missing value then\n${senderSnippet(' ')}\n set attNames to {}\n try\n set attNames to name of every attachment of theMsg\n end try\n${body}\n set out to out & ${asRow(['(id of theMsg as string)', 'sndName', 'sndAddr', 'my sanitizePositionalList(attNames)', 'bodyText'])}\n end if\n end repeat\n return out\nend tell`, 'scan');\n const details = new Map(splitRecords(raw).map(record => {\n const parts = splitFields(record);\n const detail = {\n senderName: field(parts, 1),\n senderEmail: field(parts, 2),\n attachmentNames: splitPositionalList(field(parts, 3)),\n body: field(parts, 4),\n };\n return [field(parts, 0), detail] as const;\n }));\n\n const matches: InboxSearchMatch[] = [];\n for (const candidate of candidates) {\n const detail = details.get(candidate.id);\n if (!detail) continue;\n // Attachment names only arrive with the details, so this test waits for them.\n if (request.requireAttachment && detail.attachmentNames.length === 0) continue;\n matches.push({\n entryId: candidate.id,\n storeId: '',\n subject: candidate.subject,\n senderName: detail.senderName,\n senderEmail: detail.senderEmail,\n receivedTime: candidate.receivedTime,\n body: detail.body,\n attachmentNames: detail.attachmentNames,\n folderPath: candidate.folderPath,\n });\n }\n return matches;\n}\n\n/**\n * The email currently selected — or open — in Outlook. `current messages`\n * covers both cases the Windows reader handles separately.\n *\n * Where it sits comes back as a second record, so the detail row keeps its body\n * last. A mailbox with no account object answers `account of` with missing\n * value; its root folder's id is then looked up in the profile database.\n */\nexport async function readSelectedEmail(): Promise<SelectedEmail> {\n const records = splitRecords(await runOsaScript(`tell application \"Microsoft Outlook\"\n set sel to {}\n try\n set sel to current messages\n end try\n if (count of sel) is 0 then error ${asString(`${failureTag('NOT_FOUND', 'email')}No email is selected in Outlook. Select or open an email, then try again.`)}\n set theMsg to item 1 of sel\n${messageDetailSnippet(true)}\n set acctAddr to \"\"\n try\n set rawAddr to email address of (account of theMsg)\n if rawAddr is not missing value then set acctAddr to rawAddr as string\n end try\n set chainNames to {}\n set rootId to \"\"\n set theFolder to missing value\n try\n set theFolder to folder of theMsg\n end try\n if theFolder is not missing value then\n${folderChainSnippet(' ')}\n try\n set rootId to (id of cur) as string\n end try\n end if\n return ${asRow(messageDetailFields(true))} & ${asRow(['acctAddr', 'my sanitizeList(chainNames)', 'rootId'])}\nend tell`, 'quick'));\n if (records.length === 0) throw new NotFoundError('email', 'Outlook reported no selected email.');\n const parts = splitFields(records[0]);\n const where = splitFields(records[1] ?? '');\n const chain = splitList(field(where, 1)).reverse();\n const account = field(where, 0) || (chain.length ? await accountByRootFolder(field(where, 2)) : '');\n return {\n entryId: field(parts, MessageDetail.id),\n storeId: '',\n subject: field(parts, MessageDetail.subject).trim(),\n senderName: field(parts, MessageDetail.senderName),\n senderEmail: field(parts, MessageDetail.senderEmail),\n receivedTime: field(parts, MessageDetail.receivedTime),\n body: field(parts, MessageDetail.body),\n attachmentNames: splitPositionalList(field(parts, MessageDetail.attachmentNames)),\n folderPath: account && chain.length ? macFolderPath(account, chain[0], chain.slice(1)) : '',\n };\n}\n\n/** The address of the account whose root folder has this id, per the profile database; '' if none. */\nasync function accountByRootFolder(rootId: string): Promise<string> {\n if (!/^\\d+$/.test(rootId)) return '';\n const id = Number(rootId);\n return (await readProfileAccounts()).find(a => a.folderIds['root folder'] === id)?.emailAccount ?? '';\n}\n\n/** Open an email in Outlook and bring Outlook forward. */\nexport async function openOutlookEmail(email: EmailLocator): Promise<void> {\n const id = macMessageId(email.entryId);\n await runOsaScript(`\ntell application \"Microsoft Outlook\"\n${messageLookupSnippet(id)}\n open theMsg\n activate\nend tell`, 'quick');\n}\n"]}
package/dist/mac/run.d.ts CHANGED
@@ -1,20 +1,28 @@
1
+ import { type RunBudget } from '../runtime';
2
+ import type { ItemFailure } from '../types';
1
3
  /**
2
- * Run an AppleScript via a temp file (avoids arg-length and quoting limits).
4
+ * Run a script from a temp file (no argument-length or quoting limits) and
5
+ * return what it printed, minus the newline osascript appends.
3
6
  *
4
- * `AS_HANDLERS` is prepended here rather than by each caller — the Windows runner
5
- * already owns its UTF-8 prelude the same way. It matters more on this side: a
6
- * script missing a handler fails at COMPILE time for the WHOLE script, with a
7
- * message pointing nowhere near the omission, so "remember to paste the handlers"
8
- * was a footgun every new script had to survive.
9
- *
10
- * `timeout` overrides the configured default for this one call; see `configure()`
11
- * for that and for the stdout cap.
7
+ * `AS_HANDLERS` is prepended here rather than by each caller: a script missing
8
+ * a handler fails to compile as a WHOLE, with an error pointing nowhere near the
9
+ * omission, so it can't be left to each script to remember.
10
+ */
11
+ export declare function runOsaScript(source: string, budget: RunBudget): Promise<string>;
12
+ /**
13
+ * Escape text for the inside of an AppleScript double-quoted literal.
14
+ * AppleScript strings never interpolate, so escaping the quote, the backslash
15
+ * and line breaks is the whole job.
12
16
  */
13
- export declare function runOsaScript(source: string, timeout?: number): Promise<string>;
14
- /** Escape a string for embedding inside an AppleScript double-quoted literal. */
15
- export declare function asEscape(s: string): string;
17
+ export declare function asEscape(text: string): string;
18
+ /** Text as an AppleScript string literal. */
19
+ export declare function asString(text: string): string;
16
20
  /** AppleScript's boolean literals. */
17
21
  export declare function asBool(value: boolean): string;
22
+ /** A whole number for a script; anything else is refused before it becomes code. */
23
+ export declare function asInt(value: number): string;
24
+ /** Message ids (already validated as integers) as an AppleScript list literal. */
25
+ export declare function asIdList(ids: readonly string[]): string;
18
26
  export declare const FIELD_SEP = "\u001F";
19
27
  export declare const RECORD_SEP = "\u001E";
20
28
  export declare const LIST_SEP = "\u001D";
@@ -23,42 +31,47 @@ export declare const AS_FIELD_SEP = "(character id 31)";
23
31
  export declare const AS_RECORD_SEP = "(character id 30)";
24
32
  export declare const AS_LIST_SEP = "(character id 29)";
25
33
  /**
26
- * Emit one record: the AppleScript expressions in `fields`, separated and
27
- * terminated so `splitRecords`/`splitFields` can take them apart again.
28
- *
29
- * Every field goes through `sanitize`, which is what makes the framing safe
30
- * rather than merely unlikely to break. A field holding a LIST must be built
31
- * with `my sanitizeList(...)`, which cleans the elements instead — `sanitize`
32
- * deliberately leaves the list separator alone.
34
+ * One record: the AppleScript expressions in `fields`, separated and terminated
35
+ * so `splitRecords`/`splitFields` can take them apart again. A field holding a
36
+ * LIST must be built with `my sanitizeList(...)`, which cleans the elements —
37
+ * `sanitize` deliberately leaves the list separator alone.
33
38
  */
34
39
  export declare function asRow(fields: readonly string[]): string;
35
40
  /**
36
- * The AppleScript handlers every script here relies on. Called with `my` from
37
- * inside a `tell` block.
41
+ * The handlers every script relies on, called with `my` from inside a `tell`.
38
42
  *
39
- * `isoDate` produces the zero-padded 'yyyy-MM-dd HH:mm' both platforms' readers
40
- * return; `sanitize` strips the framing characters; `joinList` and `replaceText`
41
- * are the text-item-delimiter dance nobody should write twice.
43
+ * `isoDate` produces the zero-padded 'yyyy-MM-dd HH:mm' both platforms return;
44
+ * `sanitize` strips the framing characters; `joinList` and `replaceText` are the
45
+ * text-item-delimiter dance nobody should write twice.
42
46
  */
43
- export declare const AS_HANDLERS = "\non pad2(n)\n set s to (n as integer) as string\n if (length of s) < 2 then set s to \"0\" & s\n return s\nend pad2\n\non isoDate(d)\n if d is missing value then return \"\"\n return (year of d as string) & \"-\" & pad2(month of d as integer) & \"-\" & pad2(day of d) & \" \" & pad2(hours of d) & \":\" & pad2(minutes of d)\nend isoDate\n\non joinList(lst, sep)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to sep\n set out to lst as string\n set AppleScript's text item delimiters to saved\n return out\nend joinList\n\non replaceText(t, findWhat, replaceWith)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to findWhat\n set parts to text items of t\n set AppleScript's text item delimiters to replaceWith\n set out to parts as string\n set AppleScript's text item delimiters to saved\n return out\nend replaceText\n\n-- Strips the FIELD and RECORD separators only. The LIST separator is left\n-- alone on purpose: a field may legitimately BE a list, and stripping 29 here\n-- collapsed every such field into one run-on string.\non sanitize(v)\n if v is missing value then return \"\"\n set t to v as string\n repeat with codePoint in {30, 31}\n set marker to (character id (codePoint as integer))\n if t contains marker then set t to my replaceText(t, marker, \" \")\n end repeat\n return t\nend sanitize\n\n-- A list field: each element loses all three separators, then they are joined\n-- with the LIST separator that splitList() takes them apart on.\non sanitizeList(lst)\n set cleaned to {}\n repeat with item_ in lst\n set t to my sanitize(item_)\n repeat with codePoint in {29}\n set marker to (character id (codePoint as integer))\n if t contains marker then set t to my replaceText(t, marker, \" \")\n end repeat\n set end of cleaned to t\n end repeat\n return my joinList(cleaned, (character id 29))\nend sanitizeList\n\non insertAboveQuoted(c, ins)\n if c is missing value then return ins\n set c to c as string\n if (length of c) is 0 then return ins\n -- Outlook builds a reply as a document whose own empty paragraph sits inside\n -- WordSection1; inserting straight after that tag puts the new text where the\n -- user's cursor would have been. Anything else falls back to just inside <body>.\n -- 'at' is a reserved AppleScript parameter name, so the cut point cannot be\n -- called that however naturally it reads.\n set cutPoint to my tagEnd(c, \"WordSection1>\")\n if cutPoint is 0 then set cutPoint to my tagEnd(c, \"<body\")\n if cutPoint is 0 then return ins & c\n if cutPoint is (length of c) then return c & ins\n return (text 1 thru cutPoint of c) & ins & (text (cutPoint + 1) thru -1 of c)\nend insertAboveQuoted\n\n-- 'rest' is an AppleScript term (rest of list), so the remainder cannot be\n-- called that: assigning to it compiles and then fails at run time.\non tagEnd(c, marker)\n set ix to offset of marker in c\n if ix is 0 then return 0\n if marker ends with \">\" then return ix + (length of marker) - 1\n set tailText to text ix thru -1 of c\n set gt to offset of \">\" in tailText\n if gt is 0 then return 0\n return ix + gt - 1\nend tagEnd\n";
44
- /** Split a script's output into records, dropping the trailing empty one. */
47
+ export declare const AS_HANDLERS = "\non pad2(n)\n set s to (n as integer) as string\n if (length of s) < 2 then set s to \"0\" & s\n return s\nend pad2\n\non isoDate(d)\n if d is missing value then return \"\"\n return (year of d as string) & \"-\" & pad2(month of d as integer) & \"-\" & pad2(day of d) & \" \" & pad2(hours of d) & \":\" & pad2(minutes of d)\nend isoDate\n\non joinList(lst, sep)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to sep\n set out to lst as string\n set AppleScript's text item delimiters to saved\n return out\nend joinList\n\non replaceText(t, findWhat, replaceWith)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to findWhat\n set parts to text items of t\n set AppleScript's text item delimiters to replaceWith\n set out to parts as string\n set AppleScript's text item delimiters to saved\n return out\nend replaceText\n\n-- Strips the FIELD and RECORD separators only. The LIST separator is left\n-- alone on purpose: a field may legitimately BE a list.\non sanitize(v)\n if v is missing value then return \"\"\n set t to v as string\n repeat with codePoint in {30, 31}\n set marker to (character id (codePoint as integer))\n if t contains marker then set t to my replaceText(t, marker, \" \")\n end repeat\n return t\nend sanitize\n\n-- A list field: each element loses all three separators, then they are joined\n-- with the LIST separator that splitList() takes them apart on.\non sanitizeList(lst)\n set cleaned to {}\n repeat with item_ in lst\n set t to my sanitize(item_)\n set marker to (character id 29)\n if t contains marker then set t to my replaceText(t, marker, \" \")\n set end of cleaned to t\n end repeat\n return my joinList(cleaned, (character id 29))\nend sanitizeList\n\n-- A list whose positions matter, like an email's attachments: every element is\n-- FOLLOWED by the LIST separator, so an empty element keeps its place and an\n-- empty list stays distinct from a list of one empty name. splitPositionalList()\n-- takes it apart.\non sanitizePositionalList(lst)\n if (count of lst) is 0 then return \"\"\n return my sanitizeList(lst) & (character id 29)\nend sanitizePositionalList\n\non insertAboveQuoted(c, ins)\n if c is missing value then return ins\n set c to c as string\n if (length of c) is 0 then return ins\n -- A reply's own empty paragraph sits inside WordSection1; inserting straight\n -- after that tag puts the new text where the cursor would be. Anything else\n -- falls back to just inside <body>. ('at' is a reserved parameter name, so\n -- the cut point can't be called that.)\n set cutPoint to my tagEnd(c, \"WordSection1>\")\n if cutPoint is 0 then set cutPoint to my tagEnd(c, \"<body\")\n if cutPoint is 0 then return ins & c\n if cutPoint is (length of c) then return c & ins\n return (text 1 thru cutPoint of c) & ins & (text (cutPoint + 1) thru -1 of c)\nend insertAboveQuoted\n\n-- 'rest' is an AppleScript term, so the remainder can't be called that:\n-- assigning to it compiles and then fails at run time.\non tagEnd(c, marker)\n set ix to offset of marker in c\n if ix is 0 then return 0\n if marker ends with \">\" then return ix + (length of marker) - 1\n set tailText to text ix thru -1 of c\n set gt to offset of \">\" in tailText\n if gt is 0 then return 0\n return ix + gt - 1\nend tagEnd\n";
48
+ /** A script's output as records, without the trailing empty one. */
45
49
  export declare function splitRecords(raw: string): string[];
46
- /** Split one record into its fields. */
50
+ /** One record's fields. */
47
51
  export declare function splitFields(record: string): string[];
48
- /** Split one field that carries a list. */
52
+ /**
53
+ * A field that carries a list. Empty elements are dropped, so where an index
54
+ * into the list must match Outlook's, the field is written with
55
+ * `sanitizePositionalList` and read with `splitPositionalList` instead.
56
+ */
49
57
  export declare function splitList(value: string | undefined): string[];
50
- /** A field by position — a missing field reads as ''. */
51
- export declare function field(fields: readonly string[], index: number): string;
52
58
  /**
53
- * The fields of a script's ONE summary record — the shape every mutation here
54
- * returns (counts first, then any per-item failures as further records).
59
+ * A field written by `sanitizePositionalList`: every element at its position,
60
+ * empty ones included, so index N here is item N+1 of the AppleScript list.
55
61
  */
62
+ export declare function splitPositionalList(value: string | undefined): string[];
63
+ /** A field by position; a missing field reads as ''. */
64
+ export declare function field(fields: readonly string[], index: number): string;
65
+ /** The fields of a script's first record — the summary a mutation returns ahead of any per-item rows. */
56
66
  export declare function summaryFields(raw: string): string[];
57
- /** A numeric field, defaulting to `fallback` when absent or unparsable. */
67
+ /** A numeric field, `fallback` when absent or unparsable. */
58
68
  export declare function intField(fields: readonly string[], index: number, fallback?: number): number;
59
- /**
60
- * A boolean field. AppleScript renders booleans as the bare words `true`/`false`,
61
- * so this is the counterpart of `shared/json.ts`'s coercions for the framed
62
- * output — the Windows side gets those free from ConvertFrom-Json.
63
- */
69
+ /** A boolean field; AppleScript renders booleans as the bare words true/false. */
64
70
  export declare function boolField(fields: readonly string[], index: number): boolean;
71
+ /** The record a batch script appends, inside `on error errText`, for the id `theId` it failed on. */
72
+ export declare const ITEM_FAILURE_ROW: string;
73
+ /** A batch script's output: the summary record's fields, and the items that failed. */
74
+ export declare function splitBatch(raw: string): {
75
+ summary: string[];
76
+ failed: ItemFailure[];
77
+ };
package/dist/mac/run.js CHANGED
@@ -3,114 +3,123 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AS_HANDLERS = exports.AS_LIST_SEP = exports.AS_RECORD_SEP = exports.AS_FIELD_SEP = exports.LIST_SEP = exports.RECORD_SEP = exports.FIELD_SEP = void 0;
6
+ exports.ITEM_FAILURE_ROW = exports.AS_HANDLERS = exports.AS_LIST_SEP = exports.AS_RECORD_SEP = exports.AS_FIELD_SEP = exports.LIST_SEP = exports.RECORD_SEP = exports.FIELD_SEP = void 0;
7
7
  exports.runOsaScript = runOsaScript;
8
8
  exports.asEscape = asEscape;
9
+ exports.asString = asString;
9
10
  exports.asBool = asBool;
11
+ exports.asInt = asInt;
12
+ exports.asIdList = asIdList;
10
13
  exports.asRow = asRow;
11
14
  exports.splitRecords = splitRecords;
12
15
  exports.splitFields = splitFields;
13
16
  exports.splitList = splitList;
17
+ exports.splitPositionalList = splitPositionalList;
14
18
  exports.field = field;
15
19
  exports.summaryFields = summaryFields;
16
20
  exports.intField = intField;
17
21
  exports.boolField = boolField;
22
+ exports.splitBatch = splitBatch;
18
23
  // Getting a generated AppleScript to osascript and its output back.
19
24
  //
20
- // The macOS counterpart of windows/run.ts: the run itself, the escaping rules,
21
- // and the record framing every reader here shares.
22
- const child_process_1 = require("child_process");
25
+ // The macOS counterpart of windows/run.ts: running a script, the escaping
26
+ // rules, and the record framing every reader here shares.
23
27
  const fs_1 = __importDefault(require("fs"));
24
28
  const runtime_1 = require("../runtime");
29
+ const exec_1 = require("../shared/exec");
25
30
  const errors_1 = require("../errors");
26
31
  const replyBody_1 = require("../shared/replyBody");
27
32
  const RUNNER = 'osascript';
28
33
  /**
29
- * Run an AppleScript via a temp file (avoids arg-length and quoting limits).
30
- *
31
- * `AS_HANDLERS` is prepended here rather than by each caller — the Windows runner
32
- * already owns its UTF-8 prelude the same way. It matters more on this side: a
33
- * script missing a handler fails at COMPILE time for the WHOLE script, with a
34
- * message pointing nowhere near the omission, so "remember to paste the handlers"
35
- * was a footgun every new script had to survive.
34
+ * osascript's report of a script error: "<file>:<start>:<end>: execution error:
35
+ * <message> (<number>)". Only the message is worth showing — these reach people
36
+ * in per-item failure lists — and -2700 is the number AppleScript gives every
37
+ * `error "…"` a script raises itself.
38
+ */
39
+ function parseFailure(stderr) {
40
+ const message = stderr
41
+ .replace(/^(?:.*?:)?\d+:\d+:\s*execution error:\s*/m, '')
42
+ .replace(/\s*\(-2700\)\s*$/, '')
43
+ .trim();
44
+ return { message };
45
+ }
46
+ /**
47
+ * Run a script from a temp file (no argument-length or quoting limits) and
48
+ * return what it printed, minus the newline osascript appends.
36
49
  *
37
- * `timeout` overrides the configured default for this one call; see `configure()`
38
- * for that and for the stdout cap.
50
+ * `AS_HANDLERS` is prepended here rather than by each caller: a script missing
51
+ * a handler fails to compile as a WHOLE, with an error pointing nowhere near the
52
+ * omission, so it can't be left to each script to remember.
39
53
  */
40
- function runOsaScript(source, timeout) {
41
- // The full text is what osascript compiled, so it is also what the error's
42
- // line numbers refer to and what the debug hook and ScriptError must carry.
54
+ async function runOsaScript(source, budget) {
55
+ // The full text is what osascript compiles, so it is also what error offsets
56
+ // refer to and what the debug hook and errors carry.
43
57
  const script = exports.AS_HANDLERS + source;
44
- const scriptFile = (0, runtime_1.tempFile)('osa', 'applescript');
45
- fs_1.default.writeFileSync(scriptFile, script, 'utf-8');
46
- const { timeoutMs, maxBufferBytes, signal } = (0, runtime_1.getConfig)();
47
- const effectiveTimeout = timeout ?? timeoutMs;
48
- const startedAt = Date.now();
49
- return new Promise((resolve, reject) => {
50
- (0, child_process_1.execFile)('osascript', [scriptFile], { maxBuffer: maxBufferBytes, timeout: effectiveTimeout, signal }, (error, stdout, stderr) => {
51
- const durationMs = Date.now() - startedAt;
52
- try {
53
- fs_1.default.unlinkSync(scriptFile);
54
- }
55
- catch { /* ignore */
56
- }
57
- if (error) {
58
- // Running from a file, osascript prefixes the script path:
59
- // "/tmp/outlook-bridge-osa-1.applescript:12:34: execution error:
60
- // Microsoft Outlook got an error: … (-1728)". Keep just the human
61
- // part — these strings reach the user in per-email failure lists.
62
- const msg = (stderr || error.message)
63
- .replace(/^(?:.*?:)?\d+:\d+:\s*execution error:\s*/m, '')
64
- .trim();
65
- const failure = (0, errors_1.classifyRunFailure)({
66
- runner: RUNNER,
67
- script,
68
- stderr: msg,
69
- durationMs,
70
- nodeError: error,
71
- timeoutMs: effectiveTimeout,
72
- signal,
73
- });
74
- (0, runtime_1.reportRun)({ runner: RUNNER, script, durationMs, error: failure.message });
75
- reject(failure);
76
- }
77
- else {
78
- (0, runtime_1.reportRun)({ runner: RUNNER, script, durationMs });
79
- resolve(stdout.replace(/\n$/, ''));
80
- }
58
+ const file = (0, runtime_1.tempFile)('osa', 'applescript');
59
+ fs_1.default.writeFileSync(file, script, 'utf8');
60
+ try {
61
+ const { stdout } = await (0, exec_1.runScriptProcess)({
62
+ runner: RUNNER,
63
+ command: 'osascript',
64
+ args: [file],
65
+ script,
66
+ budget,
67
+ parseFailure,
81
68
  });
82
- });
69
+ return stdout.replace(/\n$/, '');
70
+ }
71
+ finally {
72
+ (0, runtime_1.removeTempFile)(file);
73
+ }
83
74
  }
84
- /** Escape a string for embedding inside an AppleScript double-quoted literal. */
85
- function asEscape(s) {
86
- return s
75
+ /**
76
+ * Escape text for the inside of an AppleScript double-quoted literal.
77
+ * AppleScript strings never interpolate, so escaping the quote, the backslash
78
+ * and line breaks is the whole job.
79
+ */
80
+ function asEscape(text) {
81
+ return text
87
82
  .replace(/\\/g, '\\\\')
88
83
  .replace(/"/g, '\\"')
89
84
  .replace(/\r\n|\r|\n/g, '\\n');
90
85
  }
86
+ /** Text as an AppleScript string literal. */
87
+ function asString(text) {
88
+ return `"${asEscape(text)}"`;
89
+ }
91
90
  /** AppleScript's boolean literals. */
92
91
  function asBool(value) {
93
92
  return value ? 'true' : 'false';
94
93
  }
95
- // Control characters as separators: subjects and bodies contain tabs, newlines
96
- // and commas, but never these. Every emitted field also passes through the
97
- // `sanitize` handler below, which is what makes the framing safe rather than
98
- // merely unlikely to break.
99
- exports.FIELD_SEP = '\u001f';
100
- exports.RECORD_SEP = '\u001e';
101
- exports.LIST_SEP = '\u001d';
94
+ /** A whole number for a script; anything else is refused before it becomes code. */
95
+ function asInt(value) {
96
+ if (!Number.isSafeInteger(value)) {
97
+ throw new errors_1.InvalidRequestError(`Expected a whole number, got ${String(value)}.`);
98
+ }
99
+ return String(value);
100
+ }
101
+ /** Message ids (already validated as integers) as an AppleScript list literal. */
102
+ function asIdList(ids) {
103
+ return `{${ids.map(id => asInt(Number(id))).join(', ')}}`;
104
+ }
105
+ // ── Record framing ───────────────────────────────────────────────────────
106
+ //
107
+ // Control characters separate fields, records and list items: subjects and
108
+ // bodies contain tabs, newlines and commas, but never these — and every emitted
109
+ // field passes through the `sanitize` handler, which makes the framing safe
110
+ // rather than merely unlikely to break.
111
+ exports.FIELD_SEP = '';
112
+ exports.RECORD_SEP = '';
113
+ exports.LIST_SEP = '';
102
114
  /** The same three, as AppleScript expressions. */
103
115
  exports.AS_FIELD_SEP = '(character id 31)';
104
116
  exports.AS_RECORD_SEP = '(character id 30)';
105
117
  exports.AS_LIST_SEP = '(character id 29)';
106
118
  /**
107
- * Emit one record: the AppleScript expressions in `fields`, separated and
108
- * terminated so `splitRecords`/`splitFields` can take them apart again.
109
- *
110
- * Every field goes through `sanitize`, which is what makes the framing safe
111
- * rather than merely unlikely to break. A field holding a LIST must be built
112
- * with `my sanitizeList(...)`, which cleans the elements instead — `sanitize`
113
- * deliberately leaves the list separator alone.
119
+ * One record: the AppleScript expressions in `fields`, separated and terminated
120
+ * so `splitRecords`/`splitFields` can take them apart again. A field holding a
121
+ * LIST must be built with `my sanitizeList(...)`, which cleans the elements —
122
+ * `sanitize` deliberately leaves the list separator alone.
114
123
  */
115
124
  function asRow(fields) {
116
125
  return fields
@@ -118,12 +127,11 @@ function asRow(fields) {
118
127
  .join(` & ${exports.AS_FIELD_SEP} & `) + ` & ${exports.AS_RECORD_SEP}`;
119
128
  }
120
129
  /**
121
- * The AppleScript handlers every script here relies on. Called with `my` from
122
- * inside a `tell` block.
130
+ * The handlers every script relies on, called with `my` from inside a `tell`.
123
131
  *
124
- * `isoDate` produces the zero-padded 'yyyy-MM-dd HH:mm' both platforms' readers
125
- * return; `sanitize` strips the framing characters; `joinList` and `replaceText`
126
- * are the text-item-delimiter dance nobody should write twice.
132
+ * `isoDate` produces the zero-padded 'yyyy-MM-dd HH:mm' both platforms return;
133
+ * `sanitize` strips the framing characters; `joinList` and `replaceText` are the
134
+ * text-item-delimiter dance nobody should write twice.
127
135
  */
128
136
  exports.AS_HANDLERS = `
129
137
  on pad2(n)
@@ -156,8 +164,7 @@ on replaceText(t, findWhat, replaceWith)
156
164
  end replaceText
157
165
 
158
166
  -- Strips the FIELD and RECORD separators only. The LIST separator is left
159
- -- alone on purpose: a field may legitimately BE a list, and stripping 29 here
160
- -- collapsed every such field into one run-on string.
167
+ -- alone on purpose: a field may legitimately BE a list.
161
168
  on sanitize(v)
162
169
  if v is missing value then return ""
163
170
  set t to v as string
@@ -174,24 +181,30 @@ on sanitizeList(lst)
174
181
  set cleaned to {}
175
182
  repeat with item_ in lst
176
183
  set t to my sanitize(item_)
177
- repeat with codePoint in {29}
178
- set marker to (character id (codePoint as integer))
179
- if t contains marker then set t to my replaceText(t, marker, " ")
180
- end repeat
184
+ set marker to (character id 29)
185
+ if t contains marker then set t to my replaceText(t, marker, " ")
181
186
  set end of cleaned to t
182
187
  end repeat
183
188
  return my joinList(cleaned, (character id 29))
184
189
  end sanitizeList
185
190
 
191
+ -- A list whose positions matter, like an email's attachments: every element is
192
+ -- FOLLOWED by the LIST separator, so an empty element keeps its place and an
193
+ -- empty list stays distinct from a list of one empty name. splitPositionalList()
194
+ -- takes it apart.
195
+ on sanitizePositionalList(lst)
196
+ if (count of lst) is 0 then return ""
197
+ return my sanitizeList(lst) & (character id 29)
198
+ end sanitizePositionalList
199
+
186
200
  on insertAboveQuoted(c, ins)
187
201
  if c is missing value then return ins
188
202
  set c to c as string
189
203
  if (length of c) is 0 then return ins
190
- -- Outlook builds a reply as a document whose own empty paragraph sits inside
191
- -- WordSection1; inserting straight after that tag puts the new text where the
192
- -- user's cursor would have been. Anything else falls back to just inside <body>.
193
- -- 'at' is a reserved AppleScript parameter name, so the cut point cannot be
194
- -- called that however naturally it reads.
204
+ -- A reply's own empty paragraph sits inside WordSection1; inserting straight
205
+ -- after that tag puts the new text where the cursor would be. Anything else
206
+ -- falls back to just inside <body>. ('at' is a reserved parameter name, so
207
+ -- the cut point can't be called that.)
195
208
  set cutPoint to my tagEnd(c, "${replyBody_1.WORD_SECTION_ANCHOR}")
196
209
  if cutPoint is 0 then set cutPoint to my tagEnd(c, "<body")
197
210
  if cutPoint is 0 then return ins & c
@@ -199,8 +212,8 @@ on insertAboveQuoted(c, ins)
199
212
  return (text 1 thru cutPoint of c) & ins & (text (cutPoint + 1) thru -1 of c)
200
213
  end insertAboveQuoted
201
214
 
202
- -- 'rest' is an AppleScript term (rest of list), so the remainder cannot be
203
- -- called that: assigning to it compiles and then fails at run time.
215
+ -- 'rest' is an AppleScript term, so the remainder can't be called that:
216
+ -- assigning to it compiles and then fails at run time.
204
217
  on tagEnd(c, marker)
205
218
  set ix to offset of marker in c
206
219
  if ix is 0 then return 0
@@ -211,40 +224,62 @@ on tagEnd(c, marker)
211
224
  return ix + gt - 1
212
225
  end tagEnd
213
226
  `;
214
- /** Split a script's output into records, dropping the trailing empty one. */
227
+ /** A script's output as records, without the trailing empty one. */
215
228
  function splitRecords(raw) {
216
229
  return raw.split(exports.RECORD_SEP).filter(record => record.trim() !== '');
217
230
  }
218
- /** Split one record into its fields. */
231
+ /** One record's fields. */
219
232
  function splitFields(record) {
220
233
  return record.split(exports.FIELD_SEP);
221
234
  }
222
- /** Split one field that carries a list. */
235
+ /**
236
+ * A field that carries a list. Empty elements are dropped, so where an index
237
+ * into the list must match Outlook's, the field is written with
238
+ * `sanitizePositionalList` and read with `splitPositionalList` instead.
239
+ */
223
240
  function splitList(value) {
224
241
  return (value || '').split(exports.LIST_SEP).filter(Boolean);
225
242
  }
226
- /** A field by position — a missing field reads as ''. */
243
+ /**
244
+ * A field written by `sanitizePositionalList`: every element at its position,
245
+ * empty ones included, so index N here is item N+1 of the AppleScript list.
246
+ */
247
+ function splitPositionalList(value) {
248
+ return value ? value.split(exports.LIST_SEP).slice(0, -1) : [];
249
+ }
250
+ /** A field by position; a missing field reads as ''. */
227
251
  function field(fields, index) {
228
252
  return fields[index] ?? '';
229
253
  }
230
- /**
231
- * The fields of a script's ONE summary record — the shape every mutation here
232
- * returns (counts first, then any per-item failures as further records).
233
- */
254
+ /** The fields of a script's first record — the summary a mutation returns ahead of any per-item rows. */
234
255
  function summaryFields(raw) {
235
256
  return splitFields(splitRecords(raw)[0] ?? '');
236
257
  }
237
- /** A numeric field, defaulting to `fallback` when absent or unparsable. */
258
+ /** A numeric field, `fallback` when absent or unparsable. */
238
259
  function intField(fields, index, fallback = 0) {
239
260
  const parsed = Number.parseInt(field(fields, index), 10);
240
261
  return Number.isNaN(parsed) ? fallback : parsed;
241
262
  }
242
- /**
243
- * A boolean field. AppleScript renders booleans as the bare words `true`/`false`,
244
- * so this is the counterpart of `shared/json.ts`'s coercions for the framed
245
- * output — the Windows side gets those free from ConvertFrom-Json.
246
- */
263
+ /** A boolean field; AppleScript renders booleans as the bare words true/false. */
247
264
  function boolField(fields, index) {
248
265
  return field(fields, index).trim() === 'true';
249
266
  }
267
+ // ── Batches ──────────────────────────────────────────────────────────────
268
+ //
269
+ // A script acting on a list of ids returns one summary record, then one record
270
+ // per id that failed. The failure row and its decoder sit together so the two
271
+ // can't come to disagree about the field order.
272
+ /** The record a batch script appends, inside `on error errText`, for the id `theId` it failed on. */
273
+ exports.ITEM_FAILURE_ROW = asRow(['(theId as string)', 'subj', 'errText']);
274
+ /** A batch script's output: the summary record's fields, and the items that failed. */
275
+ function splitBatch(raw) {
276
+ const [summary = '', ...failures] = splitRecords(raw);
277
+ return {
278
+ summary: splitFields(summary),
279
+ failed: failures.map(record => {
280
+ const parts = splitFields(record);
281
+ return { entryId: field(parts, 0), subject: field(parts, 1), error: field(parts, 2) };
282
+ }),
283
+ };
284
+ }
250
285
  //# sourceMappingURL=run.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/mac/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/mac/run.ts"],"names":[],"mappings":"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","sourcesContent":["// Getting a generated AppleScript to osascript and its output back.\n//\n// The macOS counterpart of windows/run.ts: running a script, the escaping\n// rules, and the record framing every reader here shares.\nimport fs from 'fs';\nimport { removeTempFile, type RunBudget, tempFile } from '../runtime';\nimport { runScriptProcess } from '../shared/exec';\nimport { InvalidRequestError } from '../errors';\nimport { WORD_SECTION_ANCHOR } from '../shared/replyBody';\nimport type { ItemFailure } from '../types';\n\nconst RUNNER = 'osascript' as const;\n\n/**\n * osascript's report of a script error: \"<file>:<start>:<end>: execution error:\n * <message> (<number>)\". Only the message is worth showing — these reach people\n * in per-item failure lists — and -2700 is the number AppleScript gives every\n * `error \"…\"` a script raises itself.\n */\nfunction parseFailure(stderr: string): { message: string } {\n const message = stderr\n .replace(/^(?:.*?:)?\\d+:\\d+:\\s*execution error:\\s*/m, '')\n .replace(/\\s*\\(-2700\\)\\s*$/, '')\n .trim();\n return { message };\n}\n\n/**\n * Run a script from a temp file (no argument-length or quoting limits) and\n * return what it printed, minus the newline osascript appends.\n *\n * `AS_HANDLERS` is prepended here rather than by each caller: a script missing\n * a handler fails to compile as a WHOLE, with an error pointing nowhere near the\n * omission, so it can't be left to each script to remember.\n */\nexport async function runOsaScript(source: string, budget: RunBudget): Promise<string> {\n // The full text is what osascript compiles, so it is also what error offsets\n // refer to and what the debug hook and errors carry.\n const script = AS_HANDLERS + source;\n const file = tempFile('osa', 'applescript');\n fs.writeFileSync(file, script, 'utf8');\n try {\n const { stdout } = await runScriptProcess({\n runner: RUNNER,\n command: 'osascript',\n args: [file],\n script,\n budget,\n parseFailure,\n });\n return stdout.replace(/\\n$/, '');\n } finally {\n removeTempFile(file);\n }\n}\n\n/**\n * Escape text for the inside of an AppleScript double-quoted literal.\n * AppleScript strings never interpolate, so escaping the quote, the backslash\n * and line breaks is the whole job.\n */\nexport function asEscape(text: string): string {\n return text\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\r\\n|\\r|\\n/g, '\\\\n');\n}\n\n/** Text as an AppleScript string literal. */\nexport function asString(text: string): string {\n return `\"${asEscape(text)}\"`;\n}\n\n/** AppleScript's boolean literals. */\nexport function asBool(value: boolean): string {\n return value ? 'true' : 'false';\n}\n\n/** A whole number for a script; anything else is refused before it becomes code. */\nexport function asInt(value: number): string {\n if (!Number.isSafeInteger(value)) {\n throw new InvalidRequestError(`Expected a whole number, got ${String(value)}.`);\n }\n return String(value);\n}\n\n/** Message ids (already validated as integers) as an AppleScript list literal. */\nexport function asIdList(ids: readonly string[]): string {\n return `{${ids.map(id => asInt(Number(id))).join(', ')}}`;\n}\n\n// ── Record framing ───────────────────────────────────────────────────────\n//\n// Control characters separate fields, records and list items: subjects and\n// bodies contain tabs, newlines and commas, but never these — and every emitted\n// field passes through the `sanitize` handler, which makes the framing safe\n// rather than merely unlikely to break.\nexport const FIELD_SEP = '\u001f';\nexport const RECORD_SEP = '\u001e';\nexport const LIST_SEP = '\u001d';\n\n/** The same three, as AppleScript expressions. */\nexport const AS_FIELD_SEP = '(character id 31)';\nexport const AS_RECORD_SEP = '(character id 30)';\nexport const AS_LIST_SEP = '(character id 29)';\n\n/**\n * One record: the AppleScript expressions in `fields`, separated and terminated\n * so `splitRecords`/`splitFields` can take them apart again. A field holding a\n * LIST must be built with `my sanitizeList(...)`, which cleans the elements —\n * `sanitize` deliberately leaves the list separator alone.\n */\nexport function asRow(fields: readonly string[]): string {\n return fields\n .map(f => `my sanitize(${f})`)\n .join(` & ${AS_FIELD_SEP} & `) + ` & ${AS_RECORD_SEP}`;\n}\n\n/**\n * The handlers every script relies on, called with `my` from inside a `tell`.\n *\n * `isoDate` produces the zero-padded 'yyyy-MM-dd HH:mm' both platforms return;\n * `sanitize` strips the framing characters; `joinList` and `replaceText` are the\n * text-item-delimiter dance nobody should write twice.\n */\nexport const AS_HANDLERS = `\non pad2(n)\n set s to (n as integer) as string\n if (length of s) < 2 then set s to \"0\" & s\n return s\nend pad2\n\non isoDate(d)\n if d is missing value then return \"\"\n return (year of d as string) & \"-\" & pad2(month of d as integer) & \"-\" & pad2(day of d) & \" \" & pad2(hours of d) & \":\" & pad2(minutes of d)\nend isoDate\n\non joinList(lst, sep)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to sep\n set out to lst as string\n set AppleScript's text item delimiters to saved\n return out\nend joinList\n\non replaceText(t, findWhat, replaceWith)\n set saved to AppleScript's text item delimiters\n set AppleScript's text item delimiters to findWhat\n set parts to text items of t\n set AppleScript's text item delimiters to replaceWith\n set out to parts as string\n set AppleScript's text item delimiters to saved\n return out\nend replaceText\n\n-- Strips the FIELD and RECORD separators only. The LIST separator is left\n-- alone on purpose: a field may legitimately BE a list.\non sanitize(v)\n if v is missing value then return \"\"\n set t to v as string\n repeat with codePoint in {30, 31}\n set marker to (character id (codePoint as integer))\n if t contains marker then set t to my replaceText(t, marker, \" \")\n end repeat\n return t\nend sanitize\n\n-- A list field: each element loses all three separators, then they are joined\n-- with the LIST separator that splitList() takes them apart on.\non sanitizeList(lst)\n set cleaned to {}\n repeat with item_ in lst\n set t to my sanitize(item_)\n set marker to (character id 29)\n if t contains marker then set t to my replaceText(t, marker, \" \")\n set end of cleaned to t\n end repeat\n return my joinList(cleaned, (character id 29))\nend sanitizeList\n\n-- A list whose positions matter, like an email's attachments: every element is\n-- FOLLOWED by the LIST separator, so an empty element keeps its place and an\n-- empty list stays distinct from a list of one empty name. splitPositionalList()\n-- takes it apart.\non sanitizePositionalList(lst)\n if (count of lst) is 0 then return \"\"\n return my sanitizeList(lst) & (character id 29)\nend sanitizePositionalList\n\non insertAboveQuoted(c, ins)\n if c is missing value then return ins\n set c to c as string\n if (length of c) is 0 then return ins\n -- A reply's own empty paragraph sits inside WordSection1; inserting straight\n -- after that tag puts the new text where the cursor would be. Anything else\n -- falls back to just inside <body>. ('at' is a reserved parameter name, so\n -- the cut point can't be called that.)\n set cutPoint to my tagEnd(c, \"${WORD_SECTION_ANCHOR}\")\n if cutPoint is 0 then set cutPoint to my tagEnd(c, \"<body\")\n if cutPoint is 0 then return ins & c\n if cutPoint is (length of c) then return c & ins\n return (text 1 thru cutPoint of c) & ins & (text (cutPoint + 1) thru -1 of c)\nend insertAboveQuoted\n\n-- 'rest' is an AppleScript term, so the remainder can't be called that:\n-- assigning to it compiles and then fails at run time.\non tagEnd(c, marker)\n set ix to offset of marker in c\n if ix is 0 then return 0\n if marker ends with \">\" then return ix + (length of marker) - 1\n set tailText to text ix thru -1 of c\n set gt to offset of \">\" in tailText\n if gt is 0 then return 0\n return ix + gt - 1\nend tagEnd\n`;\n\n/** A script's output as records, without the trailing empty one. */\nexport function splitRecords(raw: string): string[] {\n return raw.split(RECORD_SEP).filter(record => record.trim() !== '');\n}\n\n/** One record's fields. */\nexport function splitFields(record: string): string[] {\n return record.split(FIELD_SEP);\n}\n\n/**\n * A field that carries a list. Empty elements are dropped, so where an index\n * into the list must match Outlook's, the field is written with\n * `sanitizePositionalList` and read with `splitPositionalList` instead.\n */\nexport function splitList(value: string | undefined): string[] {\n return (value || '').split(LIST_SEP).filter(Boolean);\n}\n\n/**\n * A field written by `sanitizePositionalList`: every element at its position,\n * empty ones included, so index N here is item N+1 of the AppleScript list.\n */\nexport function splitPositionalList(value: string | undefined): string[] {\n return value ? value.split(LIST_SEP).slice(0, -1) : [];\n}\n\n/** A field by position; a missing field reads as ''. */\nexport function field(fields: readonly string[], index: number): string {\n return fields[index] ?? '';\n}\n\n/** The fields of a script's first record — the summary a mutation returns ahead of any per-item rows. */\nexport function summaryFields(raw: string): string[] {\n return splitFields(splitRecords(raw)[0] ?? '');\n}\n\n/** A numeric field, `fallback` when absent or unparsable. */\nexport function intField(fields: readonly string[], index: number, fallback = 0): number {\n const parsed = Number.parseInt(field(fields, index), 10);\n return Number.isNaN(parsed) ? fallback : parsed;\n}\n\n/** A boolean field; AppleScript renders booleans as the bare words true/false. */\nexport function boolField(fields: readonly string[], index: number): boolean {\n return field(fields, index).trim() === 'true';\n}\n\n// ── Batches ──────────────────────────────────────────────────────────────\n//\n// A script acting on a list of ids returns one summary record, then one record\n// per id that failed. The failure row and its decoder sit together so the two\n// can't come to disagree about the field order.\n\n/** The record a batch script appends, inside `on error errText`, for the id `theId` it failed on. */\nexport const ITEM_FAILURE_ROW = asRow(['(theId as string)', 'subj', 'errText']);\n\n/** A batch script's output: the summary record's fields, and the items that failed. */\nexport function splitBatch(raw: string): { summary: string[]; failed: ItemFailure[] } {\n const [summary = '', ...failures] = splitRecords(raw);\n return {\n summary: splitFields(summary),\n failed: failures.map(record => {\n const parts = splitFields(record);\n return { entryId: field(parts, 0), subject: field(parts, 1), error: field(parts, 2) };\n }),\n };\n}\n"]}