• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oprajs / opra / 19958387866

05 Dec 2025 09:19AM UTC coverage: 80.99% (-0.2%) from 81.23%
19958387866

push

github

erayhanoglu
chore: Updated deps

3534 of 4540 branches covered (77.84%)

Branch coverage included in aggregate %.

31111 of 38237 relevant lines covered (81.36%)

218.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/angular/src/angular-backend.ts
1
// @ts-ignore
×
2
import { HttpContext, HttpHeaders, HttpParams } from '@angular/common/http';
×
3
// @ts-ignore
×
4
import * as Angular from '@angular/common/http';
×
5
import typeIs from '@browsery/type-is';
×
6
import {
×
7
  HttpBackend,
×
8
  type HttpDownloadProgressEvent,
×
9
  type HttpEvent,
×
10
  HttpEventType,
×
11
  HttpResponse,
×
12
  type HttpResponseEvent,
×
13
  type HttpResponseHeaderEvent,
×
14
  type HttpSentEvent,
×
15
  type HttpUploadProgressEvent,
×
16
} from '@opra/client';
×
17
import { isBlob } from '@opra/common';
×
18
import { Observable } from 'rxjs';
×
19
import { isReadableStreamLike } from 'rxjs/internal/util/isReadableStreamLike';
×
20
import type { StrictOmit } from 'ts-gems';
×
21

×
22
/**
×
23
 *
×
24
 * @class AngularBackend
×
25
 */
×
26
export class AngularBackend extends HttpBackend {
×
27
  defaults: AngularBackend.RequestDefaults;
×
28

×
29
  constructor(
×
30
    readonly httpClient: Angular.HttpClient,
×
31
    serviceUrl: string,
×
32
    options?: AngularBackend.Options,
×
33
  ) {
×
34
    super(serviceUrl, options);
×
35
    this.defaults = {
×
36
      ...options?.defaults,
×
37
      headers:
×
38
        options?.defaults?.headers instanceof Headers
×
39
          ? options?.defaults?.headers
×
40
          : new Headers(options?.defaults?.headers),
×
41
      params:
×
42
        options?.defaults?.params instanceof URLSearchParams
×
43
          ? options?.defaults?.params
×
44
          : new URLSearchParams(options?.defaults?.params),
×
45
    };
×
46
  }
×
47

×
48
  handle(init: AngularBackend.RequestInit): Observable<HttpEvent> {
×
49
    const requestInit = this.prepareRequest(init);
×
50
    const request = new Angular.HttpRequest(
×
51
      requestInit.method,
×
52
      requestInit.url.toString(),
×
53
      {
×
54
        ...requestInit,
×
55
        headers: new HttpHeaders(requestInit.headers),
×
56
      },
×
57
    );
×
58

×
59
    const _this = this;
×
60
    return new Observable<HttpEvent>(subscriber => {
×
61
      // Send request
×
62
      this.send(request).subscribe({
×
63
        next(event) {
×
64
          if (event.type === Angular.HttpEventType.Sent) {
×
65
            // Emit 'Sent' event
×
66
            subscriber.next({
×
67
              type: HttpEventType.Sent,
×
68
              request,
×
69
            } satisfies HttpSentEvent);
×
70
            return;
×
71
          }
×
72

×
73
          if (event.type === Angular.HttpEventType.ResponseHeader) {
×
74
            // Emit 'ResponseHeader' event
×
75
            const headersResponse = _this.createResponse({
×
76
              url: request.url,
×
77
              headers: requestInit.headers,
×
78
              status: event.status,
×
79
              statusText: event.statusText,
×
80
              hasBody:
×
81
                event.headers.has('Content-Type') ||
×
82
                event.headers.has('Content-Length'),
×
83
            }) as HttpResponse<never>;
×
84
            subscriber.next({
×
85
              request,
×
86
              type: HttpEventType.ResponseHeader,
×
87
              response: headersResponse,
×
88
            } satisfies HttpResponseHeaderEvent);
×
89
            return;
×
90
          }
×
91

×
92
          if (event.type === Angular.HttpEventType.DownloadProgress) {
×
93
            // Emit 'DownloadProgress' event
×
94
            subscriber.next({
×
95
              request,
×
96
              type: HttpEventType.DownloadProgress,
×
97
              loaded: event.loaded,
×
98
              total: event.total,
×
99
            } satisfies HttpDownloadProgressEvent);
×
100
          }
×
101

×
102
          if (event.type === Angular.HttpEventType.UploadProgress) {
×
103
            // Emit 'UploadProgress' event
×
104
            subscriber.next({
×
105
              request,
×
106
              type: HttpEventType.UploadProgress,
×
107
              loaded: event.loaded,
×
108
              total: event.total,
×
109
            } satisfies HttpUploadProgressEvent);
×
110
          }
×
111

×
112
          if (event.type === Angular.HttpEventType.Response) {
×
113
            const headers = new Headers();
×
114
            event.headers
×
115
              .keys()
×
116
              .forEach(k => headers.set(k, event.headers.get(k) || ''));
×
117
            const response = _this.createResponse({
×
118
              url: request.url,
×
119
              headers,
×
120
              status: event.status,
×
121
              statusText: event.statusText,
×
122
              hasBody: !!event.body,
×
123
              body: event.body,
×
124
            });
×
125
            // Emit 'Response' event
×
126
            subscriber.next({
×
127
              type: HttpEventType.Response,
×
128
              request,
×
129
              response,
×
130
            } satisfies HttpResponseEvent);
×
131
          }
×
132
        },
×
133
        error(error) {
×
134
          subscriber.error(error);
×
135
        },
×
136
        complete() {
×
137
          subscriber.complete();
×
138
        },
×
139
      });
×
140
    });
×
141
  }
×
142

×
143
  protected send(request: Angular.HttpRequest<any>) {
×
144
    return this.httpClient.request(request);
×
145
  }
×
146

×
147
  protected prepareRequest(
×
148
    init: AngularBackend.RequestInit,
×
149
  ): AngularBackend.RequestInit {
×
150
    const headers = init.headers || new Headers();
×
151
    const requestInit: AngularBackend.RequestInit = {
×
152
      ...init,
×
153
      headers,
×
154
    };
×
155
    this.defaults.headers.forEach((val, key) => {
×
156
      if (!headers.has(key)) headers.set(key, val);
×
157
    });
×
158
    const url = new URL(requestInit.url, this.serviceUrl);
×
159
    if (this.defaults.params.size) {
×
160
      this.defaults.params.forEach((val, key) => {
×
161
        if (!url.searchParams.has(key)) url.searchParams.set(key, val);
×
162
      });
×
163
      requestInit.url = url.toString();
×
164
    }
×
165
    if (requestInit.body) {
×
166
      let body: any;
×
167
      let contentType: string;
×
168
      if (
×
169
        typeof requestInit.body === 'string' ||
×
170
        typeof requestInit.body === 'number' ||
×
171
        typeof requestInit.body === 'boolean'
×
172
      ) {
×
173
        contentType = 'text/plain; charset=UTF-8"';
×
174
        body = String(requestInit.body);
×
175
        headers.delete('Content-Size');
×
176
      } else if (isReadableStreamLike(requestInit.body)) {
×
177
        contentType = 'application/octet-stream';
×
178
        body = requestInit.body;
×
179
      } else if (Buffer.isBuffer(requestInit.body)) {
×
180
        contentType = 'application/octet-stream';
×
181
        body = requestInit.body;
×
182
        headers.set('Content-Size', String(requestInit.body.length));
×
183
      } else if (isBlob(requestInit.body)) {
×
184
        contentType = requestInit.body.type || 'application/octet-stream';
×
185
        body = requestInit.body;
×
186
        headers.set('Content-Size', String(requestInit.body.size));
×
187
      } else {
×
188
        contentType = 'application/json';
×
189
        body = JSON.stringify(requestInit.body);
×
190
        headers.delete('Content-Size');
×
191
      }
×
192
      if (!headers.has('Content-Type') && contentType)
×
193
        headers.set('Content-Type', contentType);
×
194
      requestInit.body = body;
×
195
    }
×
196
    return requestInit;
×
197
  }
×
198

×
199
  protected createResponse(init: HttpResponse.Initiator): HttpResponse {
×
200
    return new HttpResponse(init);
×
201
  }
×
202

×
203
  protected async parseBody(fetchResponse: Response): Promise<any> {
×
204
    let body: any;
×
205
    const contentType = fetchResponse.headers.get('Content-Type') || '';
×
206
    if (typeIs.is(contentType, ['json', 'application/*+json'])) {
×
207
      body = await fetchResponse.json();
×
208
      if (typeof body === 'string') body = JSON.parse(body);
×
209
    } else if (typeIs.is(contentType, ['text']))
×
210
      body = await fetchResponse.text();
×
211
    else if (typeIs.is(contentType, ['multipart']))
×
212
      body = await fetchResponse.formData();
×
213
    else {
×
214
      const buf = await fetchResponse.arrayBuffer();
×
215
      if (buf.byteLength) body = buf;
×
216
    }
×
217
    return body;
×
218
  }
×
219
}
×
220

×
221
/**
×
222
 * @namespace AngularBackend
×
223
 */
×
224
export namespace AngularBackend {
×
225
  export interface Options extends HttpBackend.Options {
×
226
    defaults?: RequestDefaults;
×
227
  }
×
228

×
229
  export interface RequestInit extends HttpBackend.RequestInit {
×
230
    context?: HttpContext;
×
231
    reportProgress?: boolean;
×
232
    params?: HttpParams;
×
233
    responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
×
234
    withCredentials?: boolean;
×
235
  }
×
236

×
237
  export interface RequestOptions extends Pick<
×
238
    RequestInit,
×
239
    'context' | 'reportProgress' | 'withCredentials'
×
240
  > {}
×
241

×
242
  export type RequestDefaults = StrictOmit<RequestOptions, 'context'> & {
×
243
    headers: Headers;
×
244
    params: URLSearchParams;
×
245
  };
×
246
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc