pulumi-improvmx 0.1.0-alpha.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.
package/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ * linguist-generated
package/README.md ADDED
@@ -0,0 +1 @@
1
+ Manage ImprovMX email forwarding resources.
@@ -0,0 +1,5 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ // Export members:
5
+ export * from "./vars";
package/config/vars.ts ADDED
@@ -0,0 +1,20 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "../utilities";
6
+
7
+ declare var exports: any;
8
+ const __config = new pulumi.Config("improvmx");
9
+
10
+ /**
11
+ * The ImprovMX API token. Can also be set via IMPROVMX_API_TOKEN env var.
12
+ */
13
+ export declare const apiToken: string | undefined;
14
+ Object.defineProperty(exports, "apiToken", {
15
+ get() {
16
+ return __config.get("apiToken");
17
+ },
18
+ enumerable: true,
19
+ });
20
+
package/domain.ts ADDED
@@ -0,0 +1,105 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "./utilities";
6
+
7
+ /**
8
+ * Manages an ImprovMX domain for email forwarding.
9
+ */
10
+ export class Domain extends pulumi.CustomResource {
11
+ /**
12
+ * Get an existing Domain resource's state with the given name, ID, and optional extra
13
+ * properties used to qualify the lookup.
14
+ *
15
+ * @param name The _unique_ name of the resulting resource.
16
+ * @param id The _unique_ provider ID of the resource to lookup.
17
+ * @param opts Optional settings to control the behavior of the CustomResource.
18
+ */
19
+ public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): Domain {
20
+ return new Domain(name, undefined as any, { ...opts, id: id });
21
+ }
22
+
23
+ /** @internal */
24
+ public static readonly __pulumiType = 'improvmx:index:Domain';
25
+
26
+ /**
27
+ * Returns true if the given object is an instance of Domain. This is designed to work even
28
+ * when multiple copies of the Pulumi SDK have been loaded into the same process.
29
+ */
30
+ public static isInstance(obj: any): obj is Domain {
31
+ if (obj === undefined || obj === null) {
32
+ return false;
33
+ }
34
+ return obj['__pulumiType'] === Domain.__pulumiType;
35
+ }
36
+
37
+ /**
38
+ * Whether the domain's DNS is correctly configured.
39
+ */
40
+ declare public /*out*/ readonly active: pulumi.Output<boolean>;
41
+ /**
42
+ * Display name of the domain.
43
+ */
44
+ declare public /*out*/ readonly display: pulumi.Output<string>;
45
+ /**
46
+ * The domain name to register with ImprovMX.
47
+ */
48
+ declare public readonly domain: pulumi.Output<string>;
49
+ /**
50
+ * Email address for delivery notifications.
51
+ */
52
+ declare public readonly notificationEmail: pulumi.Output<string | undefined>;
53
+ /**
54
+ * Webhook URL for delivery notifications.
55
+ */
56
+ declare public readonly webhook: pulumi.Output<string | undefined>;
57
+
58
+ /**
59
+ * Create a Domain resource with the given unique name, arguments, and options.
60
+ *
61
+ * @param name The _unique_ name of the resource.
62
+ * @param args The arguments to use to populate this resource's properties.
63
+ * @param opts A bag of options that control this resource's behavior.
64
+ */
65
+ constructor(name: string, args: DomainArgs, opts?: pulumi.CustomResourceOptions) {
66
+ let resourceInputs: pulumi.Inputs = {};
67
+ opts = opts || {};
68
+ if (!opts.id) {
69
+ if (args?.domain === undefined && !opts.urn) {
70
+ throw new Error("Missing required property 'domain'");
71
+ }
72
+ resourceInputs["domain"] = args?.domain;
73
+ resourceInputs["notificationEmail"] = args?.notificationEmail;
74
+ resourceInputs["webhook"] = args?.webhook;
75
+ resourceInputs["active"] = undefined /*out*/;
76
+ resourceInputs["display"] = undefined /*out*/;
77
+ } else {
78
+ resourceInputs["active"] = undefined /*out*/;
79
+ resourceInputs["display"] = undefined /*out*/;
80
+ resourceInputs["domain"] = undefined /*out*/;
81
+ resourceInputs["notificationEmail"] = undefined /*out*/;
82
+ resourceInputs["webhook"] = undefined /*out*/;
83
+ }
84
+ opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
85
+ super(Domain.__pulumiType, name, resourceInputs, opts);
86
+ }
87
+ }
88
+
89
+ /**
90
+ * The set of arguments for constructing a Domain resource.
91
+ */
92
+ export interface DomainArgs {
93
+ /**
94
+ * The domain name to register with ImprovMX.
95
+ */
96
+ domain: pulumi.Input<string>;
97
+ /**
98
+ * Email address for delivery notifications.
99
+ */
100
+ notificationEmail?: pulumi.Input<string>;
101
+ /**
102
+ * Webhook URL for delivery notifications.
103
+ */
104
+ webhook?: pulumi.Input<string>;
105
+ }
package/emailAlias.ts ADDED
@@ -0,0 +1,99 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "./utilities";
6
+
7
+ /**
8
+ * Manages an ImprovMX email alias (forwarding rule).
9
+ */
10
+ export class EmailAlias extends pulumi.CustomResource {
11
+ /**
12
+ * Get an existing EmailAlias resource's state with the given name, ID, and optional extra
13
+ * properties used to qualify the lookup.
14
+ *
15
+ * @param name The _unique_ name of the resulting resource.
16
+ * @param id The _unique_ provider ID of the resource to lookup.
17
+ * @param opts Optional settings to control the behavior of the CustomResource.
18
+ */
19
+ public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): EmailAlias {
20
+ return new EmailAlias(name, undefined as any, { ...opts, id: id });
21
+ }
22
+
23
+ /** @internal */
24
+ public static readonly __pulumiType = 'improvmx:index:EmailAlias';
25
+
26
+ /**
27
+ * Returns true if the given object is an instance of EmailAlias. This is designed to work even
28
+ * when multiple copies of the Pulumi SDK have been loaded into the same process.
29
+ */
30
+ public static isInstance(obj: any): obj is EmailAlias {
31
+ if (obj === undefined || obj === null) {
32
+ return false;
33
+ }
34
+ return obj['__pulumiType'] === EmailAlias.__pulumiType;
35
+ }
36
+
37
+ /**
38
+ * The alias name (e.g., 'info', '*' for catch-all).
39
+ */
40
+ declare public readonly alias: pulumi.Output<string>;
41
+ /**
42
+ * The domain this alias belongs to.
43
+ */
44
+ declare public readonly domain: pulumi.Output<string>;
45
+ /**
46
+ * Comma-separated destination email addresses.
47
+ */
48
+ declare public readonly forward: pulumi.Output<string>;
49
+
50
+ /**
51
+ * Create a EmailAlias resource with the given unique name, arguments, and options.
52
+ *
53
+ * @param name The _unique_ name of the resource.
54
+ * @param args The arguments to use to populate this resource's properties.
55
+ * @param opts A bag of options that control this resource's behavior.
56
+ */
57
+ constructor(name: string, args: EmailAliasArgs, opts?: pulumi.CustomResourceOptions) {
58
+ let resourceInputs: pulumi.Inputs = {};
59
+ opts = opts || {};
60
+ if (!opts.id) {
61
+ if (args?.alias === undefined && !opts.urn) {
62
+ throw new Error("Missing required property 'alias'");
63
+ }
64
+ if (args?.domain === undefined && !opts.urn) {
65
+ throw new Error("Missing required property 'domain'");
66
+ }
67
+ if (args?.forward === undefined && !opts.urn) {
68
+ throw new Error("Missing required property 'forward'");
69
+ }
70
+ resourceInputs["alias"] = args?.alias;
71
+ resourceInputs["domain"] = args?.domain;
72
+ resourceInputs["forward"] = args?.forward;
73
+ } else {
74
+ resourceInputs["alias"] = undefined /*out*/;
75
+ resourceInputs["domain"] = undefined /*out*/;
76
+ resourceInputs["forward"] = undefined /*out*/;
77
+ }
78
+ opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
79
+ super(EmailAlias.__pulumiType, name, resourceInputs, opts);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * The set of arguments for constructing a EmailAlias resource.
85
+ */
86
+ export interface EmailAliasArgs {
87
+ /**
88
+ * The alias name (e.g., 'info', '*' for catch-all).
89
+ */
90
+ alias: pulumi.Input<string>;
91
+ /**
92
+ * The domain this alias belongs to.
93
+ */
94
+ domain: pulumi.Input<string>;
95
+ /**
96
+ * Comma-separated destination email addresses.
97
+ */
98
+ forward: pulumi.Input<string>;
99
+ }
package/index.ts ADDED
@@ -0,0 +1,60 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "./utilities";
6
+
7
+ // Export members:
8
+ export { DomainArgs } from "./domain";
9
+ export type Domain = import("./domain").Domain;
10
+ export const Domain: typeof import("./domain").Domain = null as any;
11
+ utilities.lazyLoad(exports, ["Domain"], () => require("./domain"));
12
+
13
+ export { EmailAliasArgs } from "./emailAlias";
14
+ export type EmailAlias = import("./emailAlias").EmailAlias;
15
+ export const EmailAlias: typeof import("./emailAlias").EmailAlias = null as any;
16
+ utilities.lazyLoad(exports, ["EmailAlias"], () => require("./emailAlias"));
17
+
18
+ export { ProviderArgs } from "./provider";
19
+ export type Provider = import("./provider").Provider;
20
+ export const Provider: typeof import("./provider").Provider = null as any;
21
+ utilities.lazyLoad(exports, ["Provider"], () => require("./provider"));
22
+
23
+ export { SmtpCredentialArgs } from "./smtpCredential";
24
+ export type SmtpCredential = import("./smtpCredential").SmtpCredential;
25
+ export const SmtpCredential: typeof import("./smtpCredential").SmtpCredential = null as any;
26
+ utilities.lazyLoad(exports, ["SmtpCredential"], () => require("./smtpCredential"));
27
+
28
+
29
+ // Export sub-modules:
30
+ import * as config from "./config";
31
+
32
+ export {
33
+ config,
34
+ };
35
+
36
+ const _module = {
37
+ version: utilities.getVersion(),
38
+ construct: (name: string, type: string, urn: string): pulumi.Resource => {
39
+ switch (type) {
40
+ case "improvmx:index:Domain":
41
+ return new Domain(name, <any>undefined, { urn })
42
+ case "improvmx:index:EmailAlias":
43
+ return new EmailAlias(name, <any>undefined, { urn })
44
+ case "improvmx:index:SmtpCredential":
45
+ return new SmtpCredential(name, <any>undefined, { urn })
46
+ default:
47
+ throw new Error(`unknown resource type ${type}`);
48
+ }
49
+ },
50
+ };
51
+ pulumi.runtime.registerResourceModule("improvmx", "index", _module)
52
+ pulumi.runtime.registerResourcePackage("improvmx", {
53
+ version: utilities.getVersion(),
54
+ constructProvider: (name: string, type: string, urn: string): pulumi.ProviderResource => {
55
+ if (type !== "pulumi:providers:improvmx") {
56
+ throw new Error(`unknown provider type ${type}`);
57
+ }
58
+ return new Provider(name, <any>undefined, { urn });
59
+ },
60
+ });
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "pulumi-improvmx",
3
+ "version": "0.1.0-alpha.0+dev",
4
+ "homepage": "https://improvmx.com",
5
+ "scripts": {
6
+ "build": "tsc"
7
+ },
8
+ "dependencies": {
9
+ "@pulumi/pulumi": "^3.142.0"
10
+ },
11
+ "devDependencies": {
12
+ "@types/node": "^18",
13
+ "typescript": "^4.3.5"
14
+ },
15
+ "pulumi": {
16
+ "resource": true,
17
+ "name": "improvmx",
18
+ "version": "0.1.0-alpha.0+dev"
19
+ }
20
+ }
package/provider.ts ADDED
@@ -0,0 +1,55 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "./utilities";
6
+
7
+ export class Provider extends pulumi.ProviderResource {
8
+ /** @internal */
9
+ public static readonly __pulumiType = 'improvmx';
10
+
11
+ /**
12
+ * Returns true if the given object is an instance of Provider. This is designed to work even
13
+ * when multiple copies of the Pulumi SDK have been loaded into the same process.
14
+ */
15
+ public static isInstance(obj: any): obj is Provider {
16
+ if (obj === undefined || obj === null) {
17
+ return false;
18
+ }
19
+ return obj['__pulumiType'] === "pulumi:providers:" + Provider.__pulumiType;
20
+ }
21
+
22
+ /**
23
+ * The ImprovMX API token. Can also be set via IMPROVMX_API_TOKEN env var.
24
+ */
25
+ declare public readonly apiToken: pulumi.Output<string | undefined>;
26
+
27
+ /**
28
+ * Create a Provider resource with the given unique name, arguments, and options.
29
+ *
30
+ * @param name The _unique_ name of the resource.
31
+ * @param args The arguments to use to populate this resource's properties.
32
+ * @param opts A bag of options that control this resource's behavior.
33
+ */
34
+ constructor(name: string, args?: ProviderArgs, opts?: pulumi.ResourceOptions) {
35
+ let resourceInputs: pulumi.Inputs = {};
36
+ opts = opts || {};
37
+ {
38
+ resourceInputs["apiToken"] = args?.apiToken ? pulumi.secret(args.apiToken) : undefined;
39
+ }
40
+ opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
41
+ const secretOpts = { additionalSecretOutputs: ["apiToken"] };
42
+ opts = pulumi.mergeOptions(opts, secretOpts);
43
+ super(Provider.__pulumiType, name, resourceInputs, opts);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * The set of arguments for constructing a Provider resource.
49
+ */
50
+ export interface ProviderArgs {
51
+ /**
52
+ * The ImprovMX API token. Can also be set via IMPROVMX_API_TOKEN env var.
53
+ */
54
+ apiToken?: pulumi.Input<string>;
55
+ }
@@ -0,0 +1,107 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+ import * as pulumi from "@pulumi/pulumi";
5
+ import * as utilities from "./utilities";
6
+
7
+ /**
8
+ * Manages an ImprovMX SMTP credential for sending email.
9
+ */
10
+ export class SmtpCredential extends pulumi.CustomResource {
11
+ /**
12
+ * Get an existing SmtpCredential resource's state with the given name, ID, and optional extra
13
+ * properties used to qualify the lookup.
14
+ *
15
+ * @param name The _unique_ name of the resulting resource.
16
+ * @param id The _unique_ provider ID of the resource to lookup.
17
+ * @param opts Optional settings to control the behavior of the CustomResource.
18
+ */
19
+ public static get(name: string, id: pulumi.Input<pulumi.ID>, opts?: pulumi.CustomResourceOptions): SmtpCredential {
20
+ return new SmtpCredential(name, undefined as any, { ...opts, id: id });
21
+ }
22
+
23
+ /** @internal */
24
+ public static readonly __pulumiType = 'improvmx:index:SmtpCredential';
25
+
26
+ /**
27
+ * Returns true if the given object is an instance of SmtpCredential. This is designed to work even
28
+ * when multiple copies of the Pulumi SDK have been loaded into the same process.
29
+ */
30
+ public static isInstance(obj: any): obj is SmtpCredential {
31
+ if (obj === undefined || obj === null) {
32
+ return false;
33
+ }
34
+ return obj['__pulumiType'] === SmtpCredential.__pulumiType;
35
+ }
36
+
37
+ /**
38
+ * Unix timestamp when the credential was created.
39
+ */
40
+ declare public /*out*/ readonly created: pulumi.Output<number>;
41
+ /**
42
+ * The domain this SMTP credential belongs to.
43
+ */
44
+ declare public readonly domain: pulumi.Output<string>;
45
+ /**
46
+ * The SMTP password.
47
+ */
48
+ declare public readonly password: pulumi.Output<string>;
49
+ /**
50
+ * The SMTP username.
51
+ */
52
+ declare public readonly username: pulumi.Output<string>;
53
+
54
+ /**
55
+ * Create a SmtpCredential resource with the given unique name, arguments, and options.
56
+ *
57
+ * @param name The _unique_ name of the resource.
58
+ * @param args The arguments to use to populate this resource's properties.
59
+ * @param opts A bag of options that control this resource's behavior.
60
+ */
61
+ constructor(name: string, args: SmtpCredentialArgs, opts?: pulumi.CustomResourceOptions) {
62
+ let resourceInputs: pulumi.Inputs = {};
63
+ opts = opts || {};
64
+ if (!opts.id) {
65
+ if (args?.domain === undefined && !opts.urn) {
66
+ throw new Error("Missing required property 'domain'");
67
+ }
68
+ if (args?.password === undefined && !opts.urn) {
69
+ throw new Error("Missing required property 'password'");
70
+ }
71
+ if (args?.username === undefined && !opts.urn) {
72
+ throw new Error("Missing required property 'username'");
73
+ }
74
+ resourceInputs["domain"] = args?.domain;
75
+ resourceInputs["password"] = args?.password ? pulumi.secret(args.password) : undefined;
76
+ resourceInputs["username"] = args?.username;
77
+ resourceInputs["created"] = undefined /*out*/;
78
+ } else {
79
+ resourceInputs["created"] = undefined /*out*/;
80
+ resourceInputs["domain"] = undefined /*out*/;
81
+ resourceInputs["password"] = undefined /*out*/;
82
+ resourceInputs["username"] = undefined /*out*/;
83
+ }
84
+ opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);
85
+ const secretOpts = { additionalSecretOutputs: ["password"] };
86
+ opts = pulumi.mergeOptions(opts, secretOpts);
87
+ super(SmtpCredential.__pulumiType, name, resourceInputs, opts);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * The set of arguments for constructing a SmtpCredential resource.
93
+ */
94
+ export interface SmtpCredentialArgs {
95
+ /**
96
+ * The domain this SMTP credential belongs to.
97
+ */
98
+ domain: pulumi.Input<string>;
99
+ /**
100
+ * The SMTP password.
101
+ */
102
+ password: pulumi.Input<string>;
103
+ /**
104
+ * The SMTP username.
105
+ */
106
+ username: pulumi.Input<string>;
107
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "bin",
4
+ "target": "ES2020",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "declaration": true,
8
+ "sourceMap": true,
9
+ "stripInternal": true,
10
+ "experimentalDecorators": true,
11
+ "noFallthroughCasesInSwitch": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "strict": true
14
+ },
15
+ "files": [
16
+ "config/index.ts",
17
+ "config/vars.ts",
18
+ "domain.ts",
19
+ "emailAlias.ts",
20
+ "index.ts",
21
+ "provider.ts",
22
+ "smtpCredential.ts",
23
+ "utilities.ts"
24
+ ]
25
+ }
package/utilities.ts ADDED
@@ -0,0 +1,96 @@
1
+ // *** WARNING: this file was generated by pulumi-language-nodejs. ***
2
+ // *** Do not edit by hand unless you're certain you know what you are doing! ***
3
+
4
+
5
+ import * as runtime from "@pulumi/pulumi/runtime";
6
+ import * as pulumi from "@pulumi/pulumi";
7
+
8
+ export function getEnv(...vars: string[]): string | undefined {
9
+ for (const v of vars) {
10
+ const value = process.env[v];
11
+ if (value) {
12
+ return value;
13
+ }
14
+ }
15
+ return undefined;
16
+ }
17
+
18
+ export function getEnvBoolean(...vars: string[]): boolean | undefined {
19
+ const s = getEnv(...vars);
20
+ if (s !== undefined) {
21
+ // NOTE: these values are taken from https://golang.org/src/strconv/atob.go?s=351:391#L1, which is what
22
+ // Terraform uses internally when parsing boolean values.
23
+ if (["1", "t", "T", "true", "TRUE", "True"].find(v => v === s) !== undefined) {
24
+ return true;
25
+ }
26
+ if (["0", "f", "F", "false", "FALSE", "False"].find(v => v === s) !== undefined) {
27
+ return false;
28
+ }
29
+ }
30
+ return undefined;
31
+ }
32
+
33
+ export function getEnvNumber(...vars: string[]): number | undefined {
34
+ const s = getEnv(...vars);
35
+ if (s !== undefined) {
36
+ const f = parseFloat(s);
37
+ if (!isNaN(f)) {
38
+ return f;
39
+ }
40
+ }
41
+ return undefined;
42
+ }
43
+
44
+ export function getVersion(): string {
45
+ let version = require('./package.json').version;
46
+ // Node allows for the version to be prefixed by a "v", while semver doesn't.
47
+ // If there is a v, strip it off.
48
+ if (version.indexOf('v') === 0) {
49
+ version = version.slice(1);
50
+ }
51
+ return version;
52
+ }
53
+
54
+ /** @internal */
55
+ export function resourceOptsDefaults(): any {
56
+ return { version: getVersion() };
57
+ }
58
+
59
+ /** @internal */
60
+ export function lazyLoad(exports: any, props: string[], loadModule: any) {
61
+ for (let property of props) {
62
+ Object.defineProperty(exports, property, {
63
+ enumerable: true,
64
+ get: function() {
65
+ return loadModule()[property];
66
+ },
67
+ });
68
+ }
69
+ }
70
+
71
+ /** @internal */
72
+ export async function callAsync<T>(
73
+ tok: string,
74
+ props: pulumi.Inputs,
75
+ res?: pulumi.Resource,
76
+ opts?: {property?: string},
77
+ ): Promise<T> {
78
+ const o: any = runtime.call<T>(tok, props, res);
79
+ const value = await o.promise(true /*withUnknowns*/);
80
+ const isKnown = await o.isKnown;
81
+ const isSecret = await o.isSecret;
82
+ const problem: string|undefined =
83
+ !isKnown ? "an unknown value"
84
+ : isSecret ? "a secret value"
85
+ : undefined;
86
+ // Ingoring o.resources silently. They are typically non-empty, r.f() calls include r as a dependency.
87
+ if (problem) {
88
+ throw new Error(`Plain resource method "${tok}" incorrectly returned ${problem}. ` +
89
+ "This is an error in the provider, please report this to the provider developer.");
90
+ }
91
+ // Extract a single property if requested.
92
+ if (opts && opts.property) {
93
+ return value[opts.property];
94
+ }
95
+ return value;
96
+ }