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

smart-on-fhir / client-js / 17987503568

24 Sep 2025 07:33PM UTC coverage: 95.42% (+0.8%) from 94.668%
17987503568

push

github

vlad-ignatov
Latest changes

468 of 511 branches covered (91.59%)

Branch coverage included in aggregate %.

907 of 930 relevant lines covered (97.53%)

44.24 hits per line

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

92.73
/src/adapters/NodeAdapter.ts
1
import { fhirclient } from "../types";
2
import { ready, authorize, init } from "../smart";
1✔
3
import Client from "../Client";
1✔
4
import ServerStorage from "../storage/ServerStorage";
1✔
5
import { IncomingMessage, ServerResponse } from "http";
6
import { TLSSocket } from "tls";
7
import * as security from "../security/server"
1✔
8
import { base64url } from "jose"
1✔
9

10

11
export interface NodeAdapterOptions {
12
    request: IncomingMessage;
13
    response: ServerResponse;
14
    storage?: fhirclient.Storage | fhirclient.storageFactory;
15
}
16

17
/**
18
 * Node Adapter - works with native NodeJS and with Express
19
 */
20
export default class NodeAdapter implements fhirclient.Adapter
1✔
21
{
22
    /**
23
     * Holds the Storage instance associated with this instance
24
     */
25
    protected _storage: fhirclient.Storage | null = null;
12✔
26

27
    /**
28
     * Environment-specific options
29
     */
30
    options: NodeAdapterOptions;
31

32
    security = security;
12✔
33

34
    /**
35
     * @param options Environment-specific options
36
     */
37
    constructor(options: NodeAdapterOptions)
38
    {
39
        this.options = { ...options };
12✔
40
    }
41

42
    /**
43
     * Given a relative path, returns an absolute url using the instance base URL
44
     */
45
    relative(path: string): string
46
    {
47
        return new URL(path, this.getUrl().href).href;
2✔
48
    }
49

50
    /**
51
     * Returns the protocol of the current request ("http" or "https")
52
     */
53
    getProtocol(): string
54
    {
55
        const req = this.options.request;
10✔
56
        const proto = (req.socket as TLSSocket).encrypted ? "https" : "http";
10!
57
        return req.headers["x-forwarded-proto"] as string || proto;
10✔
58
    }
59

60
    /**
61
     * Given the current environment, this method must return the current url
62
     * as URL instance. In Node we might be behind a proxy!
63
     */
64
    getUrl(): URL
65
    {
66
        const req = this.options.request;
10✔
67

68
        let host = req.headers.host;
10✔
69
        if (req.headers["x-forwarded-host"]) {
10✔
70
            host = req.headers["x-forwarded-host"] as string;
2✔
71
            if (req.headers["x-forwarded-port"] && host.indexOf(":") === -1) {
2✔
72
                host += ":" + req.headers["x-forwarded-port"];
1✔
73
            }
74
        }
75

76
        const protocol = this.getProtocol();
10✔
77
        const orig = String(req.headers["x-original-uri"] || req.url);
10✔
78
        return new URL(orig, protocol + "://" + host);
10✔
79
    }
80

81
    /**
82
     * Given the current environment, this method must redirect to the given
83
     * path
84
     * @param location The path to redirect to
85
     */
86
    redirect(location: string): void
87
    {
88
        this.options.response.writeHead(302, { location });
3✔
89
        this.options.response.end();
3✔
90
    }
91

92
    /**
93
     * Returns a ServerStorage instance
94
     */
95
    getStorage(): fhirclient.Storage
96
    {
97
        if (!this._storage) {
7✔
98
            if (this.options.storage) {
6✔
99
                if (typeof this.options.storage == "function") {
3✔
100
                    this._storage = this.options.storage(this.options);
1✔
101
                } else {
102
                    this._storage = this.options.storage;
2✔
103
                }
104
            } else {
105
                this._storage = new ServerStorage(this.options.request as fhirclient.RequestWithSession);
3✔
106
            }
107
        }
108
        return this._storage;
7✔
109
    }
110

111
    /**
112
     * Base64 to ASCII string
113
     */
114
    btoa(str: string): string
115
    {
116
        return Buffer.from(str).toString("base64");
×
117
    }
118

119
    /**
120
     * ASCII string to Base64
121
     */
122
    atob(str: string): string
123
    {
124
        return Buffer.from(str, "base64").toString("ascii");
4✔
125
    }
126

127
    base64urlencode(input: string | Uint8Array)
128
    {
129
        return base64url.encode(input);
2✔
130
    }
131

132
    base64urldecode(input: string)
133
    {
134
        return base64url.decode(input).toString();
1✔
135
    }
136

137
    /**
138
     * Creates and returns adapter-aware SMART api. Not that while the shape of
139
     * the returned object is well known, the arguments to this function are not.
140
     * Those who override this method are free to require any environment-specific
141
     * arguments. For example in node we will need a request, a response and
142
     * optionally a storage or storage factory function.
143
     */
144
    getSmartApi(): fhirclient.SMART
145
    {
146
        return {
5✔
147
            ready    : (...args: any[]) => ready(this, ...args),
2✔
148
            authorize: options => authorize(this, options),
3✔
149
            init     : options => init(this, options),
×
150
            client   : (state: string | fhirclient.ClientState) => new Client(this, state),
×
151
            options  : this.options
152
        };
153
    }
154
}
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