@dispatchtickets/sdk 0.8.0 → 0.8.2

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.
package/dist/index.d.cts CHANGED
@@ -488,6 +488,8 @@ interface PortalCreateTicketInput {
488
488
  title: string;
489
489
  /** Ticket body/description (optional) */
490
490
  body?: string;
491
+ /** IDs of pending attachments to associate with the ticket */
492
+ attachmentIds?: string[];
491
493
  }
492
494
  /**
493
495
  * Filters for listing tickets
@@ -518,6 +520,54 @@ interface PortalTicketListResponse {
518
520
  nextCursor: string | null;
519
521
  };
520
522
  }
523
+ /**
524
+ * Input for initiating an attachment upload
525
+ */
526
+ interface PortalCreateAttachmentInput {
527
+ /** Original filename */
528
+ filename: string;
529
+ /** MIME type of the file */
530
+ contentType: string;
531
+ /** File size in bytes (max 50MB) */
532
+ size: number;
533
+ }
534
+ /**
535
+ * Response from initiating an attachment upload
536
+ */
537
+ interface PortalAttachmentUploadResponse {
538
+ /** Attachment ID */
539
+ id: string;
540
+ /** Presigned URL for uploading the file (PUT request) */
541
+ uploadUrl: string;
542
+ /** URL expiration timestamp */
543
+ expiresAt: string;
544
+ }
545
+ /**
546
+ * Attachment record
547
+ */
548
+ interface PortalAttachment {
549
+ /** Attachment ID */
550
+ id: string;
551
+ /** Original filename */
552
+ filename: string;
553
+ /** MIME type */
554
+ contentType: string;
555
+ /** File size in bytes */
556
+ size: number;
557
+ /** Upload status */
558
+ status: 'pending' | 'confirmed' | 'failed';
559
+ /** Creation timestamp */
560
+ createdAt: string;
561
+ }
562
+ /**
563
+ * Attachment with download URL
564
+ */
565
+ interface PortalAttachmentWithUrl extends PortalAttachment {
566
+ /** Presigned download URL */
567
+ downloadUrl: string;
568
+ /** Download URL expiration timestamp */
569
+ expiresAt: string;
570
+ }
521
571
 
522
572
  /**
523
573
  * Brands resource for managing workspaces
@@ -1889,6 +1939,107 @@ declare class PortalTicketsResource extends BaseResource {
1889
1939
  * ```
1890
1940
  */
1891
1941
  addComment(ticketId: string, body: string, options?: PortalAddCommentOptions): Promise<PortalComment>;
1942
+ /**
1943
+ * Initiate a pending attachment upload (before ticket creation)
1944
+ *
1945
+ * Use this to upload files before creating a ticket. After uploading to the
1946
+ * presigned URL, confirm the upload, then pass the attachment IDs when
1947
+ * creating the ticket.
1948
+ *
1949
+ * @param data - Attachment metadata
1950
+ * @param options - Request options
1951
+ * @returns Upload URL and attachment ID
1952
+ *
1953
+ * @example
1954
+ * ```typescript
1955
+ * // 1. Initiate upload
1956
+ * const upload = await portal.tickets.initiatePendingUpload({
1957
+ * filename: 'screenshot.png',
1958
+ * contentType: 'image/png',
1959
+ * size: 12345,
1960
+ * });
1961
+ *
1962
+ * // 2. Upload file to presigned URL
1963
+ * await fetch(upload.uploadUrl, {
1964
+ * method: 'PUT',
1965
+ * body: fileBuffer,
1966
+ * headers: { 'Content-Type': 'image/png' },
1967
+ * });
1968
+ *
1969
+ * // 3. Confirm upload
1970
+ * await portal.tickets.confirmPendingUpload(upload.id);
1971
+ *
1972
+ * // 4. Create ticket with attachment
1973
+ * const ticket = await portal.tickets.create({
1974
+ * title: 'Bug report',
1975
+ * body: 'See attached screenshot',
1976
+ * attachmentIds: [upload.id],
1977
+ * });
1978
+ * ```
1979
+ */
1980
+ initiatePendingUpload(data: PortalCreateAttachmentInput, options?: ApiRequestOptions): Promise<PortalAttachmentUploadResponse>;
1981
+ /**
1982
+ * Confirm a pending attachment upload
1983
+ *
1984
+ * Call this after successfully uploading the file to the presigned URL.
1985
+ *
1986
+ * @param attachmentId - Attachment ID from initiatePendingUpload
1987
+ * @param options - Request options
1988
+ * @returns Confirmed attachment
1989
+ */
1990
+ confirmPendingUpload(attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachment>;
1991
+ /**
1992
+ * Initiate attachment upload for an existing ticket
1993
+ *
1994
+ * @param ticketId - Ticket ID
1995
+ * @param data - Attachment metadata
1996
+ * @param options - Request options
1997
+ * @returns Upload URL and attachment ID
1998
+ *
1999
+ * @example
2000
+ * ```typescript
2001
+ * const upload = await portal.tickets.initiateUpload('tkt_abc123', {
2002
+ * filename: 'document.pdf',
2003
+ * contentType: 'application/pdf',
2004
+ * size: 54321,
2005
+ * });
2006
+ *
2007
+ * await fetch(upload.uploadUrl, {
2008
+ * method: 'PUT',
2009
+ * body: fileBuffer,
2010
+ * headers: { 'Content-Type': 'application/pdf' },
2011
+ * });
2012
+ *
2013
+ * await portal.tickets.confirmUpload('tkt_abc123', upload.id);
2014
+ * ```
2015
+ */
2016
+ initiateUpload(ticketId: string, data: PortalCreateAttachmentInput, options?: ApiRequestOptions): Promise<PortalAttachmentUploadResponse>;
2017
+ /**
2018
+ * Confirm attachment upload for a ticket
2019
+ *
2020
+ * @param ticketId - Ticket ID
2021
+ * @param attachmentId - Attachment ID from initiateUpload
2022
+ * @param options - Request options
2023
+ * @returns Confirmed attachment
2024
+ */
2025
+ confirmUpload(ticketId: string, attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachment>;
2026
+ /**
2027
+ * List attachments on a ticket
2028
+ *
2029
+ * @param ticketId - Ticket ID
2030
+ * @param options - Request options
2031
+ * @returns Array of attachments
2032
+ */
2033
+ listAttachments(ticketId: string, options?: ApiRequestOptions): Promise<PortalAttachment[]>;
2034
+ /**
2035
+ * Get attachment with download URL
2036
+ *
2037
+ * @param ticketId - Ticket ID
2038
+ * @param attachmentId - Attachment ID
2039
+ * @param options - Request options
2040
+ * @returns Attachment with presigned download URL
2041
+ */
2042
+ getAttachment(ticketId: string, attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachmentWithUrl>;
1892
2043
  /**
1893
2044
  * Build query parameters from filters
1894
2045
  */
@@ -2343,4 +2494,4 @@ declare const webhookUtils: {
2343
2494
  */
2344
2495
  declare function collectAll<T>(iterable: AsyncIterable<T>): Promise<T[]>;
2345
2496
 
2346
- export { type Account, type AccountUsage, type ApiKey, type ApiKeyWithSecret, type ApiRequestOptions, type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type CommentCreatedData, type CommentCreatedEvent, type Company, ConflictError, type CreateApiKeyInput, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchPortal, type DispatchPortalConfig, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type EventCommentData, type EventCustomerInfo, type FieldDefinition, type FieldDefinitions, type FieldType, type GeneratePortalTokenInput, type Hooks, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, type PortalComment, type PortalCreateTicketInput, type PortalListTicketsFilters, type PortalTicket, type PortalTicketDetail, type PortalTicketListResponse, type PortalTokenResponse, RateLimitError, type RateLimitInfo, type RequestContext, type ResponseContext, type RetryConfig, type SendMagicLinkInput, ServerError, type SortOrder, type Tag, type Ticket, type TicketCreatedData, type TicketCreatedEvent, type TicketPriority, type TicketSource, type TicketStatus, type TicketUpdatedData, type TicketUpdatedEvent, TimeoutError, type UpdateApiKeyScopeInput, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookEventEnvelope, type WebhookEventMap, type WebhookEventName, type WebhookEventType, collectAll, isAuthenticationError, isCommentCreatedEvent, isConflictError, isDispatchTicketsError, isNetworkError, isNotFoundError, isRateLimitError, isServerError, isTicketCreatedEvent, isTicketUpdatedEvent, isTimeoutError, isValidationError, parseWebhookEvent, webhookUtils };
2497
+ export { type Account, type AccountUsage, type ApiKey, type ApiKeyWithSecret, type ApiRequestOptions, type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type CommentCreatedData, type CommentCreatedEvent, type Company, ConflictError, type CreateApiKeyInput, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchPortal, type DispatchPortalConfig, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type EventCommentData, type EventCustomerInfo, type FieldDefinition, type FieldDefinitions, type FieldType, type GeneratePortalTokenInput, type Hooks, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, type PortalAttachment, type PortalAttachmentUploadResponse, type PortalAttachmentWithUrl, type PortalComment, type PortalCreateAttachmentInput, type PortalCreateTicketInput, type PortalListTicketsFilters, type PortalTicket, type PortalTicketDetail, type PortalTicketListResponse, type PortalTokenResponse, RateLimitError, type RateLimitInfo, type RequestContext, type ResponseContext, type RetryConfig, type SendMagicLinkInput, ServerError, type SortOrder, type Tag, type Ticket, type TicketCreatedData, type TicketCreatedEvent, type TicketPriority, type TicketSource, type TicketStatus, type TicketUpdatedData, type TicketUpdatedEvent, TimeoutError, type UpdateApiKeyScopeInput, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookEventEnvelope, type WebhookEventMap, type WebhookEventName, type WebhookEventType, collectAll, isAuthenticationError, isCommentCreatedEvent, isConflictError, isDispatchTicketsError, isNetworkError, isNotFoundError, isRateLimitError, isServerError, isTicketCreatedEvent, isTicketUpdatedEvent, isTimeoutError, isValidationError, parseWebhookEvent, webhookUtils };
package/dist/index.d.ts CHANGED
@@ -488,6 +488,8 @@ interface PortalCreateTicketInput {
488
488
  title: string;
489
489
  /** Ticket body/description (optional) */
490
490
  body?: string;
491
+ /** IDs of pending attachments to associate with the ticket */
492
+ attachmentIds?: string[];
491
493
  }
492
494
  /**
493
495
  * Filters for listing tickets
@@ -518,6 +520,54 @@ interface PortalTicketListResponse {
518
520
  nextCursor: string | null;
519
521
  };
520
522
  }
523
+ /**
524
+ * Input for initiating an attachment upload
525
+ */
526
+ interface PortalCreateAttachmentInput {
527
+ /** Original filename */
528
+ filename: string;
529
+ /** MIME type of the file */
530
+ contentType: string;
531
+ /** File size in bytes (max 50MB) */
532
+ size: number;
533
+ }
534
+ /**
535
+ * Response from initiating an attachment upload
536
+ */
537
+ interface PortalAttachmentUploadResponse {
538
+ /** Attachment ID */
539
+ id: string;
540
+ /** Presigned URL for uploading the file (PUT request) */
541
+ uploadUrl: string;
542
+ /** URL expiration timestamp */
543
+ expiresAt: string;
544
+ }
545
+ /**
546
+ * Attachment record
547
+ */
548
+ interface PortalAttachment {
549
+ /** Attachment ID */
550
+ id: string;
551
+ /** Original filename */
552
+ filename: string;
553
+ /** MIME type */
554
+ contentType: string;
555
+ /** File size in bytes */
556
+ size: number;
557
+ /** Upload status */
558
+ status: 'pending' | 'confirmed' | 'failed';
559
+ /** Creation timestamp */
560
+ createdAt: string;
561
+ }
562
+ /**
563
+ * Attachment with download URL
564
+ */
565
+ interface PortalAttachmentWithUrl extends PortalAttachment {
566
+ /** Presigned download URL */
567
+ downloadUrl: string;
568
+ /** Download URL expiration timestamp */
569
+ expiresAt: string;
570
+ }
521
571
 
522
572
  /**
523
573
  * Brands resource for managing workspaces
@@ -1889,6 +1939,107 @@ declare class PortalTicketsResource extends BaseResource {
1889
1939
  * ```
1890
1940
  */
1891
1941
  addComment(ticketId: string, body: string, options?: PortalAddCommentOptions): Promise<PortalComment>;
1942
+ /**
1943
+ * Initiate a pending attachment upload (before ticket creation)
1944
+ *
1945
+ * Use this to upload files before creating a ticket. After uploading to the
1946
+ * presigned URL, confirm the upload, then pass the attachment IDs when
1947
+ * creating the ticket.
1948
+ *
1949
+ * @param data - Attachment metadata
1950
+ * @param options - Request options
1951
+ * @returns Upload URL and attachment ID
1952
+ *
1953
+ * @example
1954
+ * ```typescript
1955
+ * // 1. Initiate upload
1956
+ * const upload = await portal.tickets.initiatePendingUpload({
1957
+ * filename: 'screenshot.png',
1958
+ * contentType: 'image/png',
1959
+ * size: 12345,
1960
+ * });
1961
+ *
1962
+ * // 2. Upload file to presigned URL
1963
+ * await fetch(upload.uploadUrl, {
1964
+ * method: 'PUT',
1965
+ * body: fileBuffer,
1966
+ * headers: { 'Content-Type': 'image/png' },
1967
+ * });
1968
+ *
1969
+ * // 3. Confirm upload
1970
+ * await portal.tickets.confirmPendingUpload(upload.id);
1971
+ *
1972
+ * // 4. Create ticket with attachment
1973
+ * const ticket = await portal.tickets.create({
1974
+ * title: 'Bug report',
1975
+ * body: 'See attached screenshot',
1976
+ * attachmentIds: [upload.id],
1977
+ * });
1978
+ * ```
1979
+ */
1980
+ initiatePendingUpload(data: PortalCreateAttachmentInput, options?: ApiRequestOptions): Promise<PortalAttachmentUploadResponse>;
1981
+ /**
1982
+ * Confirm a pending attachment upload
1983
+ *
1984
+ * Call this after successfully uploading the file to the presigned URL.
1985
+ *
1986
+ * @param attachmentId - Attachment ID from initiatePendingUpload
1987
+ * @param options - Request options
1988
+ * @returns Confirmed attachment
1989
+ */
1990
+ confirmPendingUpload(attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachment>;
1991
+ /**
1992
+ * Initiate attachment upload for an existing ticket
1993
+ *
1994
+ * @param ticketId - Ticket ID
1995
+ * @param data - Attachment metadata
1996
+ * @param options - Request options
1997
+ * @returns Upload URL and attachment ID
1998
+ *
1999
+ * @example
2000
+ * ```typescript
2001
+ * const upload = await portal.tickets.initiateUpload('tkt_abc123', {
2002
+ * filename: 'document.pdf',
2003
+ * contentType: 'application/pdf',
2004
+ * size: 54321,
2005
+ * });
2006
+ *
2007
+ * await fetch(upload.uploadUrl, {
2008
+ * method: 'PUT',
2009
+ * body: fileBuffer,
2010
+ * headers: { 'Content-Type': 'application/pdf' },
2011
+ * });
2012
+ *
2013
+ * await portal.tickets.confirmUpload('tkt_abc123', upload.id);
2014
+ * ```
2015
+ */
2016
+ initiateUpload(ticketId: string, data: PortalCreateAttachmentInput, options?: ApiRequestOptions): Promise<PortalAttachmentUploadResponse>;
2017
+ /**
2018
+ * Confirm attachment upload for a ticket
2019
+ *
2020
+ * @param ticketId - Ticket ID
2021
+ * @param attachmentId - Attachment ID from initiateUpload
2022
+ * @param options - Request options
2023
+ * @returns Confirmed attachment
2024
+ */
2025
+ confirmUpload(ticketId: string, attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachment>;
2026
+ /**
2027
+ * List attachments on a ticket
2028
+ *
2029
+ * @param ticketId - Ticket ID
2030
+ * @param options - Request options
2031
+ * @returns Array of attachments
2032
+ */
2033
+ listAttachments(ticketId: string, options?: ApiRequestOptions): Promise<PortalAttachment[]>;
2034
+ /**
2035
+ * Get attachment with download URL
2036
+ *
2037
+ * @param ticketId - Ticket ID
2038
+ * @param attachmentId - Attachment ID
2039
+ * @param options - Request options
2040
+ * @returns Attachment with presigned download URL
2041
+ */
2042
+ getAttachment(ticketId: string, attachmentId: string, options?: ApiRequestOptions): Promise<PortalAttachmentWithUrl>;
1892
2043
  /**
1893
2044
  * Build query parameters from filters
1894
2045
  */
@@ -2343,4 +2494,4 @@ declare const webhookUtils: {
2343
2494
  */
2344
2495
  declare function collectAll<T>(iterable: AsyncIterable<T>): Promise<T[]>;
2345
2496
 
2346
- export { type Account, type AccountUsage, type ApiKey, type ApiKeyWithSecret, type ApiRequestOptions, type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type CommentCreatedData, type CommentCreatedEvent, type Company, ConflictError, type CreateApiKeyInput, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchPortal, type DispatchPortalConfig, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type EventCommentData, type EventCustomerInfo, type FieldDefinition, type FieldDefinitions, type FieldType, type GeneratePortalTokenInput, type Hooks, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, type PortalComment, type PortalCreateTicketInput, type PortalListTicketsFilters, type PortalTicket, type PortalTicketDetail, type PortalTicketListResponse, type PortalTokenResponse, RateLimitError, type RateLimitInfo, type RequestContext, type ResponseContext, type RetryConfig, type SendMagicLinkInput, ServerError, type SortOrder, type Tag, type Ticket, type TicketCreatedData, type TicketCreatedEvent, type TicketPriority, type TicketSource, type TicketStatus, type TicketUpdatedData, type TicketUpdatedEvent, TimeoutError, type UpdateApiKeyScopeInput, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookEventEnvelope, type WebhookEventMap, type WebhookEventName, type WebhookEventType, collectAll, isAuthenticationError, isCommentCreatedEvent, isConflictError, isDispatchTicketsError, isNetworkError, isNotFoundError, isRateLimitError, isServerError, isTicketCreatedEvent, isTicketUpdatedEvent, isTimeoutError, isValidationError, parseWebhookEvent, webhookUtils };
2497
+ export { type Account, type AccountUsage, type ApiKey, type ApiKeyWithSecret, type ApiRequestOptions, type Attachment, type AttachmentStatus, type AttachmentWithUrl, AuthenticationError, type AuthorType, type Brand, type BulkAction, type BulkActionResult, type Category, type CategoryStats, type Comment, type CommentCreatedData, type CommentCreatedEvent, type Company, ConflictError, type CreateApiKeyInput, type CreateBrandInput, type CreateCategoryInput, type CreateCommentInput, type CreateCommentOptions, type CreateCustomerInput, type CreateFieldInput, type CreateTagInput, type CreateTicketInput, type CreateTicketOptions, type CreateWebhookInput, type Customer, type DeleteBrandPreview, DispatchPortal, type DispatchPortalConfig, DispatchTickets, type DispatchTicketsConfig, DispatchTicketsError, type EntityType, type EventCommentData, type EventCustomerInfo, type FieldDefinition, type FieldDefinitions, type FieldType, type GeneratePortalTokenInput, type Hooks, type InitiateUploadInput, type InitiateUploadResponse, type Link, type ListCustomersFilters, type ListTicketsFilters, type MergeTagsInput, type MergeTicketsInput, NetworkError, NotFoundError, type PaginatedResponse, type PortalAttachment, type PortalAttachmentUploadResponse, type PortalAttachmentWithUrl, type PortalComment, type PortalCreateAttachmentInput, type PortalCreateTicketInput, type PortalListTicketsFilters, type PortalTicket, type PortalTicketDetail, type PortalTicketListResponse, type PortalTokenResponse, RateLimitError, type RateLimitInfo, type RequestContext, type ResponseContext, type RetryConfig, type SendMagicLinkInput, ServerError, type SortOrder, type Tag, type Ticket, type TicketCreatedData, type TicketCreatedEvent, type TicketPriority, type TicketSource, type TicketStatus, type TicketUpdatedData, type TicketUpdatedEvent, TimeoutError, type UpdateApiKeyScopeInput, type UpdateBrandInput, type UpdateCategoryInput, type UpdateCommentInput, type UpdateCustomerInput, type UpdateFieldInput, type UpdateTagInput, type UpdateTicketInput, ValidationError, type Webhook, type WebhookDelivery, type WebhookEvent, type WebhookEventEnvelope, type WebhookEventMap, type WebhookEventName, type WebhookEventType, collectAll, isAuthenticationError, isCommentCreatedEvent, isConflictError, isDispatchTicketsError, isNetworkError, isNotFoundError, isRateLimitError, isServerError, isTicketCreatedEvent, isTicketUpdatedEvent, isTimeoutError, isValidationError, parseWebhookEvent, webhookUtils };
package/dist/index.js CHANGED
@@ -237,7 +237,9 @@ var HttpClient = class {
237
237
  return delay + jitter;
238
238
  }
239
239
  buildUrl(path, query) {
240
- const url = new URL(path, this.config.baseUrl);
240
+ const base = this.config.baseUrl.endsWith("/") ? this.config.baseUrl : `${this.config.baseUrl}/`;
241
+ const normalizedPath = path.startsWith("/") ? path.slice(1) : path;
242
+ const url = new URL(normalizedPath, base);
241
243
  if (query) {
242
244
  for (const [key, value] of Object.entries(query)) {
243
245
  if (value !== void 0) {
@@ -1468,6 +1470,146 @@ var PortalTicketsResource = class extends BaseResource {
1468
1470
  signal: options?.signal
1469
1471
  });
1470
1472
  }
1473
+ // ==========================================================================
1474
+ // Attachment Methods
1475
+ // ==========================================================================
1476
+ /**
1477
+ * Initiate a pending attachment upload (before ticket creation)
1478
+ *
1479
+ * Use this to upload files before creating a ticket. After uploading to the
1480
+ * presigned URL, confirm the upload, then pass the attachment IDs when
1481
+ * creating the ticket.
1482
+ *
1483
+ * @param data - Attachment metadata
1484
+ * @param options - Request options
1485
+ * @returns Upload URL and attachment ID
1486
+ *
1487
+ * @example
1488
+ * ```typescript
1489
+ * // 1. Initiate upload
1490
+ * const upload = await portal.tickets.initiatePendingUpload({
1491
+ * filename: 'screenshot.png',
1492
+ * contentType: 'image/png',
1493
+ * size: 12345,
1494
+ * });
1495
+ *
1496
+ * // 2. Upload file to presigned URL
1497
+ * await fetch(upload.uploadUrl, {
1498
+ * method: 'PUT',
1499
+ * body: fileBuffer,
1500
+ * headers: { 'Content-Type': 'image/png' },
1501
+ * });
1502
+ *
1503
+ * // 3. Confirm upload
1504
+ * await portal.tickets.confirmPendingUpload(upload.id);
1505
+ *
1506
+ * // 4. Create ticket with attachment
1507
+ * const ticket = await portal.tickets.create({
1508
+ * title: 'Bug report',
1509
+ * body: 'See attached screenshot',
1510
+ * attachmentIds: [upload.id],
1511
+ * });
1512
+ * ```
1513
+ */
1514
+ async initiatePendingUpload(data, options) {
1515
+ return this._post(
1516
+ "/portal/tickets/attachments/pending",
1517
+ data,
1518
+ options
1519
+ );
1520
+ }
1521
+ /**
1522
+ * Confirm a pending attachment upload
1523
+ *
1524
+ * Call this after successfully uploading the file to the presigned URL.
1525
+ *
1526
+ * @param attachmentId - Attachment ID from initiatePendingUpload
1527
+ * @param options - Request options
1528
+ * @returns Confirmed attachment
1529
+ */
1530
+ async confirmPendingUpload(attachmentId, options) {
1531
+ return this._post(
1532
+ `/portal/tickets/attachments/pending/${attachmentId}/confirm`,
1533
+ {},
1534
+ options
1535
+ );
1536
+ }
1537
+ /**
1538
+ * Initiate attachment upload for an existing ticket
1539
+ *
1540
+ * @param ticketId - Ticket ID
1541
+ * @param data - Attachment metadata
1542
+ * @param options - Request options
1543
+ * @returns Upload URL and attachment ID
1544
+ *
1545
+ * @example
1546
+ * ```typescript
1547
+ * const upload = await portal.tickets.initiateUpload('tkt_abc123', {
1548
+ * filename: 'document.pdf',
1549
+ * contentType: 'application/pdf',
1550
+ * size: 54321,
1551
+ * });
1552
+ *
1553
+ * await fetch(upload.uploadUrl, {
1554
+ * method: 'PUT',
1555
+ * body: fileBuffer,
1556
+ * headers: { 'Content-Type': 'application/pdf' },
1557
+ * });
1558
+ *
1559
+ * await portal.tickets.confirmUpload('tkt_abc123', upload.id);
1560
+ * ```
1561
+ */
1562
+ async initiateUpload(ticketId, data, options) {
1563
+ return this._post(
1564
+ `/portal/tickets/${ticketId}/attachments`,
1565
+ data,
1566
+ options
1567
+ );
1568
+ }
1569
+ /**
1570
+ * Confirm attachment upload for a ticket
1571
+ *
1572
+ * @param ticketId - Ticket ID
1573
+ * @param attachmentId - Attachment ID from initiateUpload
1574
+ * @param options - Request options
1575
+ * @returns Confirmed attachment
1576
+ */
1577
+ async confirmUpload(ticketId, attachmentId, options) {
1578
+ return this._post(
1579
+ `/portal/tickets/${ticketId}/attachments/${attachmentId}/confirm`,
1580
+ {},
1581
+ options
1582
+ );
1583
+ }
1584
+ /**
1585
+ * List attachments on a ticket
1586
+ *
1587
+ * @param ticketId - Ticket ID
1588
+ * @param options - Request options
1589
+ * @returns Array of attachments
1590
+ */
1591
+ async listAttachments(ticketId, options) {
1592
+ return this._get(
1593
+ `/portal/tickets/${ticketId}/attachments`,
1594
+ void 0,
1595
+ options
1596
+ );
1597
+ }
1598
+ /**
1599
+ * Get attachment with download URL
1600
+ *
1601
+ * @param ticketId - Ticket ID
1602
+ * @param attachmentId - Attachment ID
1603
+ * @param options - Request options
1604
+ * @returns Attachment with presigned download URL
1605
+ */
1606
+ async getAttachment(ticketId, attachmentId, options) {
1607
+ return this._get(
1608
+ `/portal/tickets/${ticketId}/attachments/${attachmentId}`,
1609
+ void 0,
1610
+ options
1611
+ );
1612
+ }
1471
1613
  /**
1472
1614
  * Build query parameters from filters
1473
1615
  */