@sendmux/cli 1.0.1 → 1.2.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 (35) hide show
  1. package/README.md +63 -8
  2. package/dist/base-command.d.ts +2 -2
  3. package/dist/base-command.d.ts.map +1 -1
  4. package/dist/base-command.js +4 -4
  5. package/dist/commands/mailbox/create-attachment-upload.d.ts +26 -0
  6. package/dist/commands/mailbox/create-attachment-upload.d.ts.map +1 -0
  7. package/dist/commands/mailbox/create-attachment-upload.js +7 -0
  8. package/dist/commands/mailbox/get-message-attachment.d.ts +6 -0
  9. package/dist/commands/mailbox/get-message-attachment.d.ts.map +1 -1
  10. package/dist/commands/mailbox/stream-events.d.ts +18 -0
  11. package/dist/commands/mailbox/stream-events.d.ts.map +1 -1
  12. package/dist/commands/mailbox/stream-events.js +8 -0
  13. package/dist/commands/management/check-mailbox-availability.d.ts +26 -0
  14. package/dist/commands/management/check-mailbox-availability.d.ts.map +1 -0
  15. package/dist/commands/management/check-mailbox-availability.js +7 -0
  16. package/dist/commands/sending/get-open-api-spec.d.ts +1 -1
  17. package/dist/commands/sending/send/batch.d.ts +1 -1
  18. package/dist/commands/sending/send.d.ts +1 -1
  19. package/dist/generated/operations.d.ts +53 -5
  20. package/dist/generated/operations.d.ts.map +1 -1
  21. package/dist/generated/operations.js +56 -3
  22. package/dist/key-kind.d.ts +3 -0
  23. package/dist/key-kind.d.ts.map +1 -1
  24. package/dist/key-kind.js +13 -1
  25. package/dist/operation-command.d.ts +4 -0
  26. package/dist/operation-command.d.ts.map +1 -1
  27. package/dist/operation-flags.d.ts +9 -0
  28. package/dist/operation-flags.d.ts.map +1 -1
  29. package/dist/operation-flags.js +29 -4
  30. package/dist/operation-runner.d.ts.map +1 -1
  31. package/dist/operation-runner.js +282 -0
  32. package/dist/operation-types.d.ts +2 -2
  33. package/dist/operation-types.d.ts.map +1 -1
  34. package/oclif.manifest.json +3002 -104
  35. package/package.json +2 -2
@@ -1,14 +1,19 @@
1
1
  import { type AuthFlags, type SendmuxCommand } from "./base-command.js";
2
2
  import type { OperationDefinition } from "./operation-types.js";
3
3
  export interface OperationFlags extends AuthFlags {
4
+ attach?: string[];
4
5
  body?: string;
5
6
  "body-file"?: string;
7
+ "content-type"?: string;
8
+ file?: string;
9
+ follow?: boolean;
6
10
  header?: string[];
7
11
  "idempotency-key"?: string;
8
12
  "if-match"?: string;
9
13
  "if-none-match"?: string;
10
14
  path?: string[];
11
15
  query?: string[];
16
+ "via-presigned"?: boolean;
12
17
  }
13
18
  export interface ParsedOperationOptions {
14
19
  body?: unknown;
@@ -17,14 +22,18 @@ export interface ParsedOperationOptions {
17
22
  query?: Record<string, unknown>;
18
23
  }
19
24
  export declare const operationFlags: {
25
+ attach: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
26
  body: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
21
27
  "body-file": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
28
+ "content-type": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
29
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
30
  header: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
31
  "idempotency-key": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
32
  "if-match": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
25
33
  "if-none-match": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
26
34
  path: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
27
35
  query: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
36
+ "via-presigned": import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
37
  "api-key": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
29
38
  "base-url": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
30
39
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -1 +1 @@
1
- {"version":3,"file":"operation-flags.d.ts","sourceRoot":"","sources":["../src/operation-flags.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;CA6B1B,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC"}
1
+ {"version":3,"file":"operation-flags.d.ts","sourceRoot":"","sources":["../src/operation-flags.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,mBAAmB,EAGpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAe,SAAQ,SAAS;IAC/C,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;CA0C1B,CAAC;AAEF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC"}
@@ -3,12 +3,22 @@ import { readFile } from "node:fs/promises";
3
3
  import { authFlags, } from "./base-command.js";
4
4
  export const operationFlags = {
5
5
  ...authFlags,
6
+ attach: Flags.string({
7
+ description: "Local file path to attach to mailbox:send-message or sending:send. Repeat for multiple files.",
8
+ multiple: true,
9
+ }),
6
10
  body: Flags.string({
7
11
  description: "JSON request body, or UTF-8 bytes for binary operations.",
8
12
  }),
9
13
  "body-file": Flags.string({
10
14
  description: "Path to a JSON request body file, or a binary file for binary operations.",
11
15
  }),
16
+ "content-type": Flags.string({
17
+ description: "Override the inferred Content-Type for --file or --attach.",
18
+ }),
19
+ file: Flags.string({
20
+ description: "Local file path for attachment upload convenience commands.",
21
+ }),
12
22
  header: Flags.string({
13
23
  description: "Header as name=value. Repeat for multiple headers.",
14
24
  multiple: true,
@@ -30,10 +40,13 @@ export const operationFlags = {
30
40
  description: "Query parameter as name=value. Repeat for multiple query parameters.",
31
41
  multiple: true,
32
42
  }),
43
+ "via-presigned": Flags.boolean({
44
+ description: "For mailbox:upload-attachment --file, mint a short-lived upload URL and PUT the file without sending an API key.",
45
+ }),
33
46
  };
34
47
  export async function parseOperationOptions(command, operation, flags) {
35
48
  const path = parseParameterPairs(command, operation.pathParams, flags.path ?? [], "--path");
36
- const query = parseParameterPairs(command, operation.queryParams, flags.query ?? [], "--query");
49
+ const query = parseParameterPairs(command, operation.queryParams, flags.query ?? [], "--query", fileSuppliedQueryParams(operation, flags));
37
50
  const headers = parseParameterPairs(command, operation.headerParams, flags.header ?? [], "--header");
38
51
  if (flags["idempotency-key"]) {
39
52
  addHeaderFlag(command, operation, headers, "Idempotency-Key", flags["idempotency-key"]);
@@ -52,7 +65,7 @@ export async function parseOperationOptions(command, operation, flags) {
52
65
  query,
53
66
  });
54
67
  }
55
- function parseParameterPairs(command, parameters, values, flagName) {
68
+ function parseParameterPairs(command, parameters, values, flagName, suppliedByConvenienceFlag = new Set()) {
56
69
  const parameterMap = new Map(parameters.map((parameter) => [keyForParameter(flagName, parameter.name), parameter]));
57
70
  const pairs = {};
58
71
  for (const value of values) {
@@ -83,7 +96,7 @@ function parseParameterPairs(command, parameters, values, flagName) {
83
96
  pairs[parameter.name] = parsedValue;
84
97
  }
85
98
  for (const parameter of parameters) {
86
- if (parameter.required && pairs[parameter.name] === undefined) {
99
+ if (parameter.required && pairs[parameter.name] === undefined && !suppliedByConvenienceFlag.has(parameter.name)) {
87
100
  command.error(`Missing ${labelForFlag(flagName)} parameter "${parameter.name}". Pass ${flagName} ${parameter.name}=<value>.`, {
88
101
  exit: 2,
89
102
  });
@@ -101,6 +114,9 @@ function parseParameterPairs(command, parameters, values, flagName) {
101
114
  return pairs;
102
115
  }
103
116
  async function parseBody(command, operation, flags) {
117
+ if (flags.file && (flags.body || flags["body-file"])) {
118
+ command.error("Pass only one of --file, --body, or --body-file.", { exit: 2 });
119
+ }
104
120
  if (flags.body && flags["body-file"]) {
105
121
  command.error("Pass only one of --body or --body-file.", { exit: 2 });
106
122
  }
@@ -112,7 +128,7 @@ async function parseBody(command, operation, flags) {
112
128
  }
113
129
  const hasBodyInput = flags.body !== undefined || flags["body-file"] !== undefined;
114
130
  if (!hasBodyInput) {
115
- if (operation.requestBodyRequired) {
131
+ if (operation.requestBodyRequired && !fileSuppliesBody(operation, flags)) {
116
132
  const label = operation.bodyKind === "binary" ? "request body file" : "JSON body";
117
133
  command.error(`This command requires a ${label}. Pass --body${operation.bodyKind === "binary" ? "-file" : " or --body-file"}.`, {
118
134
  exit: 2,
@@ -137,6 +153,15 @@ async function parseBody(command, operation, flags) {
137
153
  command.error("Request body must be valid JSON.", { exit: 2 });
138
154
  }
139
155
  }
156
+ function fileSuppliesBody(operation, flags) {
157
+ return Boolean(flags.file) && operation.operationId === "mailboxUploadAttachment";
158
+ }
159
+ function fileSuppliedQueryParams(operation, flags) {
160
+ if (flags.file && operation.operationId === "mailboxUploadAttachment") {
161
+ return new Set(["filename"]);
162
+ }
163
+ return new Set();
164
+ }
140
165
  function addHeaderFlag(command, operation, headers, name, value) {
141
166
  const parameter = operation.headerParams.find((item) => item.name.toLowerCase() === name.toLowerCase());
142
167
  if (!parameter) {
@@ -1 +1 @@
1
- {"version":3,"file":"operation-runner.d.ts","sourceRoot":"","sources":["../src/operation-runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAoBhE,wBAAsB,eAAe,CACnC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,OAAO,CAAC,CA4ClB"}
1
+ {"version":3,"file":"operation-runner.d.ts","sourceRoot":"","sources":["../src/operation-runner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAqBhE,wBAAsB,eAAe,CACnC,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,mBAAmB,EAC9B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,OAAO,CAAC,CAkElB"}
@@ -1,4 +1,6 @@
1
1
  import * as sdk from "@sendmux/sdk";
2
+ import { readFile, stat } from "node:fs/promises";
3
+ import { basename, extname } from "node:path";
2
4
  import { parseOperationOptions, } from "./operation-flags.js";
3
5
  const surfaceModules = {
4
6
  mailbox: sdk.mailbox,
@@ -11,6 +13,7 @@ const clientFactories = {
11
13
  sending: sdk.sending.createSendingClient,
12
14
  };
13
15
  export async function runSdkOperation(command, operation, flags) {
16
+ validateAttachmentConvenienceFlags(command, operation, flags);
14
17
  const auth = await command.resolveAuth(flags, operation.requiredKeyKind);
15
18
  const clientConfig = {
16
19
  apiKey: auth.apiKey,
@@ -19,6 +22,20 @@ export async function runSdkOperation(command, operation, flags) {
19
22
  const client = clientFactories[operation.surface](clientConfig);
20
23
  const operationOptions = await parseOperationOptions(command, operation, flags);
21
24
  const sdkOperation = operationFor(operation);
25
+ if (operation.operationId === "mailboxCreateAttachmentUpload" && flags.file) {
26
+ return createMailboxAttachmentUploadFromFile(command, client, operationOptions, flags);
27
+ }
28
+ if (operation.operationId === "mailboxUploadAttachment" && flags.file) {
29
+ return uploadMailboxAttachmentFromFile(command, client, operationOptions, flags);
30
+ }
31
+ if ((operation.operationId === "mailboxSendMessage" || operation.operationId === "sendingSendEmail") && flags.attach?.length) {
32
+ const nextOptions = await withAttachedFiles(command, operation, client, operationOptions, flags);
33
+ const response = await sdkOperation({
34
+ client,
35
+ ...nextOptions,
36
+ });
37
+ return command.renderResult(rawResponseData(response));
38
+ }
22
39
  if (operation.operationId === "mailboxStreamEvents") {
23
40
  const controller = new AbortController();
24
41
  const response = await sdkOperation({
@@ -26,6 +43,9 @@ export async function runSdkOperation(command, operation, flags) {
26
43
  ...operationOptions,
27
44
  signal: controller.signal,
28
45
  });
46
+ if (flags.follow) {
47
+ return streamEvents(command, response, controller);
48
+ }
29
49
  return command.renderResult(await firstStreamEvent(response, controller));
30
50
  }
31
51
  if (operation.operationId === "mailboxGetMessageAttachment") {
@@ -50,6 +70,241 @@ export async function runSdkOperation(command, operation, flags) {
50
70
  }
51
71
  return command.renderResult(data);
52
72
  }
73
+ function validateAttachmentConvenienceFlags(command, operation, flags) {
74
+ const supportsFile = operation.operationId === "mailboxUploadAttachment" || operation.operationId === "mailboxCreateAttachmentUpload";
75
+ if (flags.file && !supportsFile) {
76
+ command.error("This command does not support --file. Use --attach on send commands.", { exit: 2 });
77
+ }
78
+ if (flags["via-presigned"] && operation.operationId !== "mailboxUploadAttachment") {
79
+ command.error("--via-presigned is only supported by mailbox:upload-attachment --file.", { exit: 2 });
80
+ }
81
+ const supportsAttach = operation.operationId === "mailboxSendMessage" || operation.operationId === "sendingSendEmail";
82
+ if (flags.attach?.length && !supportsAttach) {
83
+ command.error("--attach is only supported by mailbox:send-message and sending:send.", { exit: 2 });
84
+ }
85
+ if (flags.attach?.length && flags["content-type"] && flags.attach.length > 1) {
86
+ command.error("--content-type with multiple --attach files would apply the same type to every file. Omit it to infer per file.", {
87
+ exit: 2,
88
+ });
89
+ }
90
+ }
91
+ async function createMailboxAttachmentUploadFromFile(command, client, operationOptions, flags) {
92
+ const file = await readAttachmentFile(command, flags.file, flags["content-type"]);
93
+ const response = await sdk.mailbox.mailboxCreateAttachmentUpload({
94
+ client: client,
95
+ body: {
96
+ content_type: file.contentType,
97
+ filename: file.filename,
98
+ size_bytes: file.sizeBytes,
99
+ },
100
+ query: mailboxUploadQuery(operationOptions),
101
+ });
102
+ return command.renderResult(rawResponseData(response));
103
+ }
104
+ async function uploadMailboxAttachmentFromFile(command, client, operationOptions, flags) {
105
+ const file = await readAttachmentFile(command, flags.file, flags["content-type"]);
106
+ if (flags["via-presigned"]) {
107
+ const intentResponse = await sdk.mailbox.mailboxCreateAttachmentUpload({
108
+ client: client,
109
+ query: mailboxUploadQuery(operationOptions),
110
+ body: {
111
+ content_type: file.contentType,
112
+ filename: file.filename,
113
+ size_bytes: file.sizeBytes,
114
+ },
115
+ });
116
+ const intent = envelopeData(intentResponse, "mailboxCreateAttachmentUpload");
117
+ const uploadUrl = stringField(intent, "upload_url", "mailboxCreateAttachmentUpload");
118
+ const method = stringField(intent, "method", "mailboxCreateAttachmentUpload");
119
+ const headers = recordField(intent, "headers", "mailboxCreateAttachmentUpload");
120
+ const contentType = stringField(headers, "Content-Type", "mailboxCreateAttachmentUpload headers");
121
+ const contentLength = stringField(headers, "Content-Length", "mailboxCreateAttachmentUpload headers");
122
+ if (method !== "PUT") {
123
+ throw new Error(`mailboxCreateAttachmentUpload returned unsupported method ${method}`);
124
+ }
125
+ const putResponse = await fetch(uploadUrl, {
126
+ body: arrayBufferFor(file.bytes),
127
+ headers: {
128
+ "Content-Length": contentLength,
129
+ "Content-Type": contentType,
130
+ },
131
+ method,
132
+ });
133
+ const payload = await putResponse.json().catch(() => undefined);
134
+ if (!putResponse.ok) {
135
+ throw new Error(`Presigned attachment upload failed with HTTP ${putResponse.status}`);
136
+ }
137
+ return command.renderResult(payload);
138
+ }
139
+ const response = await sdk.mailbox.mailboxUploadAttachment({
140
+ client: client,
141
+ body: blobFor(file),
142
+ headers: {
143
+ ...(recordOrUndefined(operationOptions.headers)),
144
+ "Content-Type": file.contentType,
145
+ },
146
+ query: {
147
+ ...mailboxUploadQuery(operationOptions),
148
+ filename: file.filename,
149
+ },
150
+ });
151
+ return command.renderResult(rawResponseData(response));
152
+ }
153
+ async function withAttachedFiles(command, operation, client, operationOptions, flags) {
154
+ const body = jsonObjectBody(command, operationOptions.body);
155
+ const existingAttachments = attachmentArray(command, body.attachments);
156
+ const files = [];
157
+ for (const path of flags.attach ?? []) {
158
+ files.push(await readAttachmentFile(command, path, flags["content-type"]));
159
+ }
160
+ if (operation.operationId === "mailboxSendMessage") {
161
+ const uploaded = [];
162
+ for (const file of files) {
163
+ const uploadResponse = await sdk.mailbox.mailboxUploadAttachment({
164
+ client: client,
165
+ body: blobFor(file),
166
+ headers: {
167
+ "Content-Type": file.contentType,
168
+ },
169
+ query: {
170
+ ...mailboxUploadQuery(operationOptions),
171
+ filename: file.filename,
172
+ },
173
+ });
174
+ const result = envelopeData(uploadResponse, "mailboxUploadAttachment");
175
+ uploaded.push({
176
+ blob_id: stringField(result, "blob_id", "mailboxUploadAttachment"),
177
+ content_type: stringField(result, "content_type", "mailboxUploadAttachment"),
178
+ filename: stringField(result, "filename", "mailboxUploadAttachment"),
179
+ });
180
+ }
181
+ return {
182
+ ...operationOptions,
183
+ body: {
184
+ ...body,
185
+ attachments: [...existingAttachments, ...uploaded],
186
+ },
187
+ };
188
+ }
189
+ return {
190
+ ...operationOptions,
191
+ body: {
192
+ ...body,
193
+ attachments: [
194
+ ...existingAttachments,
195
+ ...files.map((file) => ({
196
+ content: file.bytes.toString("base64"),
197
+ encoding: "base64",
198
+ filename: file.filename,
199
+ type: file.contentType,
200
+ })),
201
+ ],
202
+ },
203
+ };
204
+ }
205
+ async function readAttachmentFile(command, filePath, contentTypeOverride) {
206
+ const info = await stat(filePath).catch((error) => {
207
+ const message = error instanceof Error ? error.message : String(error);
208
+ command.error(`Could not read attachment file ${filePath}: ${message}`, { exit: 2 });
209
+ });
210
+ if (!info.isFile()) {
211
+ command.error(`Attachment path is not a regular file: ${filePath}`, { exit: 2 });
212
+ }
213
+ if (info.size === 0) {
214
+ command.error(`Attachment file is empty: ${filePath}`, { exit: 2 });
215
+ }
216
+ const bytes = await readFile(filePath);
217
+ return {
218
+ bytes,
219
+ contentType: contentTypeOverride ?? inferContentType(filePath),
220
+ filename: basename(filePath),
221
+ sizeBytes: bytes.byteLength,
222
+ };
223
+ }
224
+ function inferContentType(filePath) {
225
+ switch (extname(filePath).toLowerCase()) {
226
+ case ".csv":
227
+ return "text/csv";
228
+ case ".gif":
229
+ return "image/gif";
230
+ case ".htm":
231
+ case ".html":
232
+ return "text/html";
233
+ case ".jpeg":
234
+ case ".jpg":
235
+ return "image/jpeg";
236
+ case ".json":
237
+ return "application/json";
238
+ case ".md":
239
+ case ".txt":
240
+ return "text/plain";
241
+ case ".pdf":
242
+ return "application/pdf";
243
+ case ".png":
244
+ return "image/png";
245
+ case ".webp":
246
+ return "image/webp";
247
+ case ".zip":
248
+ return "application/zip";
249
+ default:
250
+ return "application/octet-stream";
251
+ }
252
+ }
253
+ function jsonObjectBody(command, value) {
254
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
255
+ command.error("--attach requires a JSON object request body.", { exit: 2 });
256
+ }
257
+ return value;
258
+ }
259
+ function attachmentArray(command, value) {
260
+ if (value === undefined) {
261
+ return [];
262
+ }
263
+ if (!Array.isArray(value)) {
264
+ command.error('Request body field "attachments" must be an array when using --attach.', { exit: 2 });
265
+ }
266
+ return value;
267
+ }
268
+ function mailboxUploadQuery(operationOptions) {
269
+ const mailboxId = recordOrUndefined(operationOptions.query)?.mailbox_id;
270
+ return typeof mailboxId === "string" && mailboxId.length > 0 ? { mailbox_id: mailboxId } : {};
271
+ }
272
+ function envelopeData(value, operationId) {
273
+ const raw = rawResponseData(value);
274
+ if (!raw || typeof raw !== "object" || !("data" in raw)) {
275
+ throw new Error(`SDK operation ${operationId} did not return an API envelope`);
276
+ }
277
+ const data = raw.data;
278
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
279
+ throw new Error(`SDK operation ${operationId} did not return object data`);
280
+ }
281
+ return data;
282
+ }
283
+ function stringField(record, field, source) {
284
+ const value = record[field];
285
+ if (typeof value !== "string" || value.length === 0) {
286
+ throw new Error(`${source} did not return string field ${field}`);
287
+ }
288
+ return value;
289
+ }
290
+ function recordField(record, field, source) {
291
+ const value = record[field];
292
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
293
+ throw new Error(`${source} did not return object field ${field}`);
294
+ }
295
+ return value;
296
+ }
297
+ function recordOrUndefined(value) {
298
+ return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
299
+ }
300
+ function blobFor(file) {
301
+ return new Blob([arrayBufferFor(file.bytes)], { type: file.contentType });
302
+ }
303
+ function arrayBufferFor(bytes) {
304
+ const copy = new Uint8Array(bytes.byteLength);
305
+ copy.set(bytes);
306
+ return copy.buffer;
307
+ }
53
308
  async function firstStreamEvent(value, controller) {
54
309
  const stream = value?.stream;
55
310
  if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
@@ -75,6 +330,33 @@ async function firstStreamEvent(value, controller) {
75
330
  await closeAsyncIterator(iterator);
76
331
  }
77
332
  }
333
+ async function streamEvents(command, value, controller) {
334
+ const stream = value?.stream;
335
+ if (!stream || typeof stream[Symbol.asyncIterator] !== "function") {
336
+ throw new Error("SDK operation mailboxStreamEvents did not return an async stream");
337
+ }
338
+ const iterator = stream[Symbol.asyncIterator]();
339
+ const abort = () => {
340
+ controller.abort();
341
+ };
342
+ process.once("SIGINT", abort);
343
+ process.once("SIGTERM", abort);
344
+ try {
345
+ while (true) {
346
+ const next = await iterator.next();
347
+ if (next.done) {
348
+ return;
349
+ }
350
+ command.log(JSON.stringify(next.value));
351
+ }
352
+ }
353
+ finally {
354
+ process.off("SIGINT", abort);
355
+ process.off("SIGTERM", abort);
356
+ controller.abort();
357
+ await closeAsyncIterator(iterator);
358
+ }
359
+ }
78
360
  async function closeAsyncIterator(iterator) {
79
361
  if (typeof iterator.return !== "function") {
80
362
  return;
@@ -1,4 +1,4 @@
1
- import type { ApiKeyKind } from "./key-kind.js";
1
+ import type { RequiredApiKeyKind } from "./key-kind.js";
2
2
  export interface OperationParameter {
3
3
  name: string;
4
4
  required: boolean;
@@ -32,7 +32,7 @@ export interface OperationDefinition {
32
32
  queryParams: readonly OperationParameter[];
33
33
  responseKind: "binary" | "json" | "text";
34
34
  requestBodyRequired: boolean;
35
- requiredKeyKind: ApiKeyKind;
35
+ requiredKeyKind: RequiredApiKeyKind;
36
36
  surface: "mailbox" | "management" | "sending";
37
37
  }
38
38
  //# sourceMappingURL=operation-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"operation-types.d.ts","sourceRoot":"","sources":["../src/operation-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAED,MAAM,MAAM,wBAAwB,GAAG,6BAA6B,GAAG,8BAA8B,CAAC;AAEtG,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,8BAA8B,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC1C,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC3C,YAAY,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,EAAE,UAAU,CAAC;IAC5B,OAAO,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;CAC/C"}
1
+ {"version":3,"file":"operation-types.d.ts","sourceRoot":"","sources":["../src/operation-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,wBAAwB,CAAC;CAClC;AAED,MAAM,MAAM,wBAAwB,GAAG,6BAA6B,GAAG,8BAA8B,CAAC;AAEtG,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,8BAA8B,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,8BAA8B;IAC7C,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC1C,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC3C,YAAY,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,eAAe,EAAE,kBAAkB,CAAC;IACpC,OAAO,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;CAC/C"}