@openemail/sdk 0.0.5 → 0.0.7

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/index.js CHANGED
@@ -24,7 +24,7 @@ const BROADCAST_RECIPIENT_FILTERS = {
24
24
  UNSUBSCRIBED: 'unsubscribed'
25
25
  };
26
26
 
27
- var version = "0.0.5";
27
+ var version = "0.0.7";
28
28
 
29
29
  const BUILD_BASE_URL = 'https://api.openemail.uk';
30
30
 
@@ -38,8 +38,8 @@ const DEFAULTS = {
38
38
  const BROWSER_REFUSAL = [
39
39
  'OpenEmail refused to start in a browser.',
40
40
  '',
41
- ' This client carries a workspace API key that can send mail and read the mailbox. Anything',
42
- ' you ship to a browser is readable by anyone who opens devtools.',
41
+ ' This client carries a workspace API key or an OAuth access token that can send mail and read',
42
+ ' the mailbox. Anything you ship to a browser is readable by anyone who opens devtools.',
43
43
  '',
44
44
  ' Call it from a server, a serverless function or a script instead. Disposable inboxes are',
45
45
  ' the exception: createTempMail() needs no API key and is safe to use in a browser.',
@@ -49,6 +49,7 @@ const BROWSER_REFUSAL = [
49
49
  ].join('\n');
50
50
  const ENV_VARS = {
51
51
  API_KEY: 'OPENEMAIL_API_KEY',
52
+ ACCESS_TOKEN: 'OPENEMAIL_ACCESS_TOKEN',
52
53
  BASE_URL: 'OPENEMAIL_BASE_URL'
53
54
  };
54
55
  const API_KEY_PREFIXES = {
@@ -59,10 +60,22 @@ const API_KEY_MODES = {
59
60
  LIVE: 'live',
60
61
  TEST: 'test'
61
62
  };
63
+ const ACCESS_TOKEN_RULES = {
64
+ RESERVED_PREFIX: 'oe_',
65
+ MAX_LENGTH: 512
66
+ };
67
+ const CREDENTIAL_KINDS = {
68
+ API_KEY: 'apiKey',
69
+ OAUTH: 'oauth'
70
+ };
62
71
  const CLIENT_MESSAGES = {
63
72
  API_KEY_REQUIRED: `An OpenEmail API key is required. Pass { apiKey } or set ${ENV_VARS.API_KEY}. Create one in OpenEmail under Settings, API keys.`,
64
- API_KEY_SHAPE: 'is not an OpenEmail API key. The API accepts only keys beginning "oe_live_" or "oe_test_", so a session cookie, a session token or a key for another service is refused.',
65
- BASE_URL_SHAPE: 'is not a usable base URL. Pass an origin such as "https://api.openemail.uk", or the http origin of a server you run yourself.',
73
+ CREDENTIAL_REQUIRED: `An OpenEmail API key or OAuth access token is required. Pass { apiKey } or { accessToken }, or set ${ENV_VARS.API_KEY} or ${ENV_VARS.ACCESS_TOKEN}. Create a key in OpenEmail under Settings, API keys.`,
74
+ CREDENTIAL_CONFLICT: 'Pass { apiKey } or { accessToken }, not both. Every request carries one credential, so the client cannot tell which of the two you meant.',
75
+ API_KEY_SHAPE: 'is not an OpenEmail API key. The API accepts only keys beginning "oe_live_" or "oe_test_", so a session cookie, a session token or a key for another service is refused. Pass an OAuth access token as { accessToken } instead.',
76
+ ACCESS_TOKEN_SHAPE: `is not an OAuth access token. Pass the access token OpenEmail issued when the app was connected: a string of 1 to ${ACCESS_TOKEN_RULES.MAX_LENGTH} characters that does not begin "${ACCESS_TOKEN_RULES.RESERVED_PREFIX}". An API key goes in { apiKey } instead.`,
77
+ ACCESS_TOKEN_PROVIDED: 'The value the { accessToken } function resolved to',
78
+ BASE_URL_SHAPE: 'is not a usable base URL. Pass an https origin such as "https://api.openemail.uk". Plain http is for a server on this machine only, at localhost, a 127.x.x.x address or ::1, because the client never sends a credential over plain http to any other host.',
66
79
  NO_FETCH: 'No global fetch is available. Pass one as { fetch }, or run on Node 20+, Bun, Deno, Cloudflare Workers or a browser.',
67
80
  EMPTY_SEGMENT: 'An id must not be empty.',
68
81
  FILENAME_REQUIRED: 'A file name is required. Pass it as { filename }, the name the file is stored and downloaded under.',
@@ -552,6 +565,8 @@ const PATHS = {
552
565
  TRACKING_STATS: '/tracking/stats',
553
566
  CALENDAR_EVENTS: '/calendar/events',
554
567
  SETTINGS: '/settings',
568
+ SECURITY_STEP_UP: '/security/step-up',
569
+ SECURITY_STEP_UP_VERIFY: '/security/step-up/verify',
555
570
  ROLES: '/roles',
556
571
  ROLES_PERMISSIONS: '/roles/permissions',
557
572
  MEMBERS: '/members',
@@ -707,6 +722,20 @@ const API_SCOPES = {
707
722
  KEYS_MANAGE: 'keys:manage'
708
723
  };
709
724
 
725
+ const STEP_UP_METHODS = {
726
+ EMAIL: 'email',
727
+ TOTP: 'totp'
728
+ };
729
+ const STEP_UP_ERROR_CODES = {
730
+ STEP_UP_REQUIRED: 'step_up_required',
731
+ STEP_UP_NOT_APPLICABLE: 'step_up_not_applicable',
732
+ STEP_UP_THROTTLED: 'step_up_throttled',
733
+ STEP_UP_UNDELIVERABLE: 'step_up_undeliverable',
734
+ STEP_UP_CODE_INVALID: 'step_up_code_invalid',
735
+ STEP_UP_CODE_EXPIRED: 'step_up_code_expired',
736
+ STEP_UP_LOCKED: 'step_up_locked'
737
+ };
738
+
710
739
  const SUPPRESSION_REASONS = {
711
740
  BOUNCE: 'bounce',
712
741
  COMPLAINT: 'complaint',
@@ -779,7 +808,12 @@ const WEBHOOK_SIGNATURE_HEADERS = WEBHOOK_HEADERS;
779
808
  const CLIENT_REGISTRY_KEY = Symbol.for('openemail.sdk.client.v1');
780
809
  const CLIENT_REGISTRY = globalThis;
781
810
 
782
- const LOCAL_HOSTS = ['localhost', '127.0.0.1', '0.0.0.0', '::1'];
811
+ const LOOPBACK_HOSTNAMES = ['localhost', '::1', '[::1]'];
812
+ const LOOPBACK_IPV4_PATTERN = /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
813
+ const LOOPBACK_IPV4_ADDRESS = '127.0.0.1';
814
+ const LOOPBACK_IPV6_ADDRESS = '[::1]';
815
+ const UNSPECIFIED_HOSTNAMES = ['0.0.0.0', '::', '[::]'];
816
+ const LOCAL_HOSTS = [...LOOPBACK_HOSTNAMES, LOOPBACK_IPV4_ADDRESS, ...UNSPECIFIED_HOSTNAMES];
783
817
  const ENDPOINT_SCHEME_PATTERN = /^[a-z][a-z0-9+.-]*:\/\//i;
784
818
 
785
819
  const RETRYABLE_STATUSES = new Set(RETRY.STATUSES);
@@ -888,13 +922,36 @@ const RETRYABLE_METHODS = new Set(RETRY.METHODS);
888
922
  scopes: [API_SCOPES.WEBHOOKS_READ]});
889
923
 
890
924
  const IsApiKey = (value) => typeof value === 'string' && (value.startsWith(API_KEY_PREFIXES.LIVE) || value.startsWith(API_KEY_PREFIXES.TEST));
891
- const ModeOf = (apiKey) => apiKey.startsWith(API_KEY_PREFIXES.TEST) ? API_KEY_MODES.TEST : API_KEY_MODES.LIVE;
925
+ const IsAccessToken = (value) => typeof value === 'string'
926
+ && value.length > 0
927
+ && value.length <= ACCESS_TOKEN_RULES.MAX_LENGTH
928
+ && !value.startsWith(ACCESS_TOKEN_RULES.RESERVED_PREFIX);
929
+ const IsPresent = (value) => value !== undefined && value !== null && value !== '';
930
+ const ModeOf = (apiKey) => apiKey?.startsWith(API_KEY_PREFIXES.TEST) ? API_KEY_MODES.TEST : API_KEY_MODES.LIVE;
892
931
  const AssertApiKey = (apiKey, where) => {
893
932
  if (!apiKey)
894
933
  throw new Error(CLIENT_MESSAGES.API_KEY_REQUIRED);
895
934
  if (!IsApiKey(apiKey))
896
935
  throw new Error(`${where} ${CLIENT_MESSAGES.API_KEY_SHAPE}`);
897
936
  };
937
+ const AssertAccessToken = (accessToken, where) => {
938
+ if (typeof accessToken === 'function')
939
+ return;
940
+ if (!IsAccessToken(accessToken))
941
+ throw new Error(`${where} ${CLIENT_MESSAGES.ACCESS_TOKEN_SHAPE}`);
942
+ };
943
+ const AssertCredential = (apiKey, accessToken, required) => {
944
+ const withKey = IsPresent(apiKey);
945
+ const withToken = IsPresent(accessToken);
946
+ if (withKey && withToken)
947
+ throw new Error(CLIENT_MESSAGES.CREDENTIAL_CONFLICT);
948
+ if (withKey)
949
+ AssertApiKey(apiKey, '{ apiKey }');
950
+ else if (withToken)
951
+ AssertAccessToken(accessToken, '{ accessToken }');
952
+ else if (required)
953
+ throw new Error(CLIENT_MESSAGES.CREDENTIAL_REQUIRED);
954
+ };
898
955
 
899
956
  const IsBrowser = () => {
900
957
  const scope = globalThis;
@@ -932,6 +989,9 @@ class OpenEmailApiError extends Error {
932
989
  get isScopeMissing() {
933
990
  return this.code === ERROR_CODES.INSUFFICIENT_SCOPE;
934
991
  }
992
+ get isStepUpRequired() {
993
+ return this.code === STEP_UP_ERROR_CODES.STEP_UP_REQUIRED;
994
+ }
935
995
  get isInvalidRequest() {
936
996
  return this.type === ERROR_TYPES.INVALID_REQUEST_ERROR;
937
997
  }
@@ -1031,8 +1091,25 @@ const Backoff = (attempt) => {
1031
1091
  return Math.round(ceiling * (0.5 + Math.random() * 0.5));
1032
1092
  };
1033
1093
 
1034
- const BuildUrl = (baseUrl, path, query) => {
1094
+ const PATH_SHAPE = 'is not a usable request path. Pass a path on the API that begins with a single "/", such as "/threads". Anything else could send the request, and the credential it carries, to another host.';
1095
+ const OFF_ORIGIN = 'leaves the API origin, so the request was not sent. Pass a path on the API that begins with a single "/", such as "/threads".';
1096
+ const ApiUrl = (baseUrl, path) => {
1097
+ if (typeof path !== 'string' || !path.startsWith('/') || path.startsWith('//') || path.startsWith('/\\')) {
1098
+ throw new Error(`${JSON.stringify(path)} ${PATH_SHAPE}`);
1099
+ }
1035
1100
  const url = `${baseUrl.replace(/\/+$/, '')}${path}`;
1101
+ let origin = null;
1102
+ try {
1103
+ origin = new URL(url).origin;
1104
+ }
1105
+ catch { }
1106
+ if (origin === null || origin !== new URL(baseUrl).origin)
1107
+ throw new Error(`${JSON.stringify(path)} ${OFF_ORIGIN}`);
1108
+ return url;
1109
+ };
1110
+
1111
+ const BuildUrl = (baseUrl, path, query) => {
1112
+ const url = ApiUrl(baseUrl, path);
1036
1113
  if (!query)
1037
1114
  return url;
1038
1115
  const params = new URLSearchParams();
@@ -1045,6 +1122,8 @@ const BuildUrl = (baseUrl, path, query) => {
1045
1122
  return serialized ? `${url}?${serialized}` : url;
1046
1123
  };
1047
1124
 
1125
+ const CleartextCredentialMessage = (baseUrl) => `Refused to send a credential to ${baseUrl} over plain http, where anyone on the network can read it. Use an https base URL. Plain http is accepted only for a server on this machine: localhost, a 127.x.x.x address or ::1.`;
1126
+
1048
1127
  const Deadline = (timeoutMs, signal) => {
1049
1128
  const controller = new AbortController();
1050
1129
  let expired = false;
@@ -1083,6 +1162,23 @@ const IdempotencyKey = () => {
1083
1162
  return `${IDEMPOTENCY_KEY_PREFIX}${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 14)}`;
1084
1163
  };
1085
1164
 
1165
+ const IsLoopbackHost = (hostname) => {
1166
+ const host = hostname.toLowerCase();
1167
+ return LOOPBACK_HOSTNAMES.includes(host) || LOOPBACK_IPV4_PATTERN.test(host);
1168
+ };
1169
+
1170
+ const IsSecureOrigin = (url) => {
1171
+ try {
1172
+ const parsed = new URL(url);
1173
+ return parsed.protocol === 'https:' || (parsed.protocol === 'http:' && IsLoopbackHost(parsed.hostname));
1174
+ }
1175
+ catch {
1176
+ return false;
1177
+ }
1178
+ };
1179
+
1180
+ const IsUnspecifiedHost = (hostname) => UNSPECIFIED_HOSTNAMES.includes(hostname.toLowerCase());
1181
+
1086
1182
  const RetryAfter = (value) => {
1087
1183
  if (!value)
1088
1184
  return undefined;
@@ -1141,6 +1237,13 @@ const ToErrorProps = (response, body, rawText, retryAfterSeconds) => {
1141
1237
  };
1142
1238
  };
1143
1239
 
1240
+ const Substitute = (url) => {
1241
+ const suggestion = new URL(url.href);
1242
+ suggestion.hostname = url.hostname.startsWith('[') ? LOOPBACK_IPV6_ADDRESS : LOOPBACK_IPV4_ADDRESS;
1243
+ return suggestion.href.replace(/\/+$/, '');
1244
+ };
1245
+ const UnspecifiedHostMessage = (baseUrl, url) => `${JSON.stringify(baseUrl)} names ${url.hostname}, an address a server listens on, not one to send requests to. For a server on this machine, use ${Substitute(url)}.`;
1246
+
1144
1247
  const Describe = (error) => error instanceof Error ? error.message : String(error);
1145
1248
  const ParseJson = (text) => {
1146
1249
  if (!text)
@@ -1152,34 +1255,45 @@ const ParseJson = (text) => {
1152
1255
  return undefined;
1153
1256
  }
1154
1257
  };
1155
- const ValidBaseUrl = (value) => {
1156
- const trimmed = value.trim().replace(/\/+$/, '');
1258
+ const ParseBaseUrl = (value) => {
1157
1259
  try {
1158
- const parsed = new URL(trimmed);
1159
- if (parsed.protocol === 'https:' || parsed.protocol === 'http:')
1160
- return trimmed;
1260
+ const parsed = new URL(value);
1261
+ return parsed.protocol === 'https:' || parsed.protocol === 'http:' ? parsed : undefined;
1262
+ }
1263
+ catch {
1264
+ return undefined;
1161
1265
  }
1162
- catch { }
1163
- throw new Error(`${JSON.stringify(value)} ${CLIENT_MESSAGES.BASE_URL_SHAPE}`);
1266
+ };
1267
+ const ValidBaseUrl = (value) => {
1268
+ const trimmed = value.trim().replace(/\/+$/, '');
1269
+ const parsed = ParseBaseUrl(trimmed);
1270
+ if (!parsed)
1271
+ throw new Error(`${JSON.stringify(value)} ${CLIENT_MESSAGES.BASE_URL_SHAPE}`);
1272
+ if (IsUnspecifiedHost(parsed.hostname))
1273
+ throw new Error(UnspecifiedHostMessage(value, parsed));
1274
+ return trimmed;
1164
1275
  };
1165
1276
  class Transport {
1166
1277
  #apiKey;
1278
+ #accessToken;
1167
1279
  #inboxToken;
1168
1280
  baseUrl;
1281
+ #secureOrigin;
1169
1282
  fetchImpl;
1170
1283
  maxRetries;
1171
1284
  timeoutMs;
1172
1285
  userAgent;
1173
1286
  headers;
1174
1287
  constructor(options) {
1175
- if (options.apiKey !== undefined)
1176
- AssertApiKey(options.apiKey, '{ apiKey }');
1288
+ AssertCredential(options.apiKey, options.accessToken, false);
1177
1289
  const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
1178
1290
  if (!fetchImpl)
1179
1291
  throw new Error(CLIENT_MESSAGES.NO_FETCH);
1180
- this.#apiKey = options.apiKey;
1292
+ this.#apiKey = IsPresent(options.apiKey) ? options.apiKey : undefined;
1293
+ this.#accessToken = IsPresent(options.accessToken) ? options.accessToken : undefined;
1181
1294
  this.#inboxToken = options.inboxToken;
1182
1295
  this.baseUrl = ValidBaseUrl(options.baseUrl ?? DEFAULTS.BASE_URL);
1296
+ this.#secureOrigin = IsSecureOrigin(this.baseUrl);
1183
1297
  this.fetchImpl = fetchImpl;
1184
1298
  this.maxRetries = Math.max(0, options.maxRetries ?? DEFAULTS.MAX_RETRIES);
1185
1299
  this.timeoutMs = options.timeoutMs ?? DEFAULTS.TIMEOUT_MS;
@@ -1191,7 +1305,7 @@ class Transport {
1191
1305
  async request(path, options = {}) {
1192
1306
  const method = (options.method ?? HTTP_METHODS.GET).toUpperCase();
1193
1307
  const url = BuildUrl(this.baseUrl, path, options.query);
1194
- const headers = this.headersFor(options);
1308
+ const headers = await this.headersFor(options);
1195
1309
  const body = options.raw !== undefined
1196
1310
  ? options.raw
1197
1311
  : options.body === undefined ? undefined : JSON.stringify(options.body);
@@ -1223,7 +1337,16 @@ class Transport {
1223
1337
  throw new OpenEmailApiError(ToErrorProps(response, ParseJson(text), text, retryAfter));
1224
1338
  }
1225
1339
  }
1226
- headersFor(options) {
1340
+ async resolveAccessToken() {
1341
+ const source = this.#accessToken;
1342
+ if (typeof source !== 'function')
1343
+ return source;
1344
+ const token = await source();
1345
+ if (!IsAccessToken(token))
1346
+ throw new Error(`${CLIENT_MESSAGES.ACCESS_TOKEN_PROVIDED} ${CLIENT_MESSAGES.ACCESS_TOKEN_SHAPE}`);
1347
+ return token;
1348
+ }
1349
+ async headersFor(options) {
1227
1350
  const headers = {
1228
1351
  ...this.headers,
1229
1352
  [HEADER_KEYS.ACCEPT]: options.accept ?? CONTENT_TYPES.JSON
@@ -1237,7 +1360,10 @@ class Transport {
1237
1360
  if (options.anonymous !== true) {
1238
1361
  if (options.apiKey !== undefined)
1239
1362
  AssertApiKey(options.apiKey, '{ apiKey } on this call');
1240
- const credential = options.inboxToken ?? options.apiKey ?? this.#inboxToken ?? this.#apiKey;
1363
+ const direct = options.inboxToken ?? options.apiKey ?? this.#inboxToken ?? this.#apiKey;
1364
+ if ((direct ?? this.#accessToken) && !this.#secureOrigin)
1365
+ throw new Error(CleartextCredentialMessage(this.baseUrl));
1366
+ const credential = direct ?? await this.resolveAccessToken();
1241
1367
  if (credential)
1242
1368
  headers[HEADER_KEYS.AUTHORIZATION] = `Bearer ${credential}`;
1243
1369
  }
@@ -2295,6 +2421,22 @@ const Rules = (transport) => ({
2295
2421
  iterateRuns: (options = {}) => IteratePages(transport, PATHS.RULES_RUNS, CURSOR_STYLES.CURSOR, options, RunsQuery(options))
2296
2422
  });
2297
2423
 
2424
+ const Security = (transport) => ({
2425
+ stepUpStatus: (options = {}) => transport.request(PATHS.SECURITY_STEP_UP, { signal: options.signal, apiKey: options.apiKey }),
2426
+ beginStepUp: (body = {}, options = {}) => transport.request(PATHS.SECURITY_STEP_UP, {
2427
+ method: HTTP_METHODS.POST,
2428
+ body,
2429
+ signal: options.signal,
2430
+ apiKey: options.apiKey
2431
+ }),
2432
+ verifyStepUp: (body, options = {}) => transport.request(PATHS.SECURITY_STEP_UP_VERIFY, {
2433
+ method: HTTP_METHODS.POST,
2434
+ body,
2435
+ signal: options.signal,
2436
+ apiKey: options.apiKey
2437
+ })
2438
+ });
2439
+
2298
2440
  const Settings = (transport) => ({
2299
2441
  get: (options = {}) => transport.request(PATHS.SETTINGS, {
2300
2442
  query: { [QUERY_KEYS.ADDRESS]: options.address },
@@ -2683,6 +2825,7 @@ class OpenEmail {
2683
2825
  transport;
2684
2826
  mode;
2685
2827
  me;
2828
+ security;
2686
2829
  keys;
2687
2830
  addresses;
2688
2831
  languages;
@@ -2709,12 +2852,13 @@ class OpenEmail {
2709
2852
  tempMail;
2710
2853
  constructor(configuration) {
2711
2854
  const options = typeof configuration === 'string' ? { apiKey: configuration } : configuration;
2712
- AssertApiKey(options.apiKey, '{ apiKey }');
2855
+ AssertCredential(options.apiKey, options.accessToken, true);
2713
2856
  if (IsBrowser() && options.dangerouslyAllowBrowser !== true)
2714
2857
  throw new Error(BROWSER_REFUSAL);
2715
2858
  this.transport = new Transport(options);
2716
2859
  this.mode = ModeOf(options.apiKey);
2717
2860
  this.me = Me(this.transport);
2861
+ this.security = Security(this.transport);
2718
2862
  this.keys = Keys(this.transport);
2719
2863
  this.addresses = Addresses(this.transport);
2720
2864
  this.languages = Languages(this.transport);
@@ -2756,6 +2900,19 @@ const FromEnvironment = (name) => {
2756
2900
  }
2757
2901
  };
2758
2902
 
2903
+ const IsLocalHost = (hostname) => {
2904
+ const host = hostname.toLowerCase();
2905
+ return LOCAL_HOSTS.includes(host) || LOOPBACK_IPV4_PATTERN.test(host);
2906
+ };
2907
+
2908
+ const HostnameOf = (authority) => {
2909
+ try {
2910
+ return new URL(`http://${authority}`).hostname;
2911
+ }
2912
+ catch {
2913
+ return '';
2914
+ }
2915
+ };
2759
2916
  const NormaliseEndpoint = (value) => {
2760
2917
  if (!value)
2761
2918
  return undefined;
@@ -2764,15 +2921,18 @@ const NormaliseEndpoint = (value) => {
2764
2921
  return undefined;
2765
2922
  if (ENDPOINT_SCHEME_PATTERN.test(trimmed))
2766
2923
  return trimmed;
2767
- const host = trimmed.split(':')[0];
2768
- return `${LOCAL_HOSTS.includes(host) ? 'http' : 'https'}://${trimmed}`;
2924
+ return `${IsLocalHost(HostnameOf(trimmed)) ? 'http' : 'https'}://${trimmed}`;
2769
2925
  };
2770
2926
 
2771
2927
  const CreateClient = (configuration = {}) => {
2772
2928
  const options = typeof configuration === 'string' ? { apiKey: configuration } : configuration;
2929
+ const explicit = options.apiKey !== undefined || options.accessToken !== undefined;
2930
+ const apiKey = explicit ? options.apiKey : FromEnvironment(ENV_VARS.API_KEY);
2931
+ const accessToken = explicit || apiKey !== undefined ? options.accessToken : FromEnvironment(ENV_VARS.ACCESS_TOKEN);
2773
2932
  return new OpenEmail({
2774
2933
  ...options,
2775
- apiKey: options.apiKey ?? FromEnvironment(ENV_VARS.API_KEY),
2934
+ apiKey,
2935
+ accessToken,
2776
2936
  baseUrl: NormaliseEndpoint(options.baseUrl ?? FromEnvironment(ENV_VARS.BASE_URL))
2777
2937
  });
2778
2938
  };
@@ -2780,6 +2940,7 @@ const CreateClient = (configuration = {}) => {
2780
2940
  const CreateTempMail = (options = {}) => TempMail(new Transport({
2781
2941
  ...options,
2782
2942
  apiKey: undefined,
2943
+ accessToken: undefined,
2783
2944
  baseUrl: NormaliseEndpoint(options.baseUrl ?? FromEnvironment(ENV_VARS.BASE_URL))
2784
2945
  }));
2785
2946
 
@@ -2907,9 +3068,10 @@ const createTempMail = CreateTempMail;
2907
3068
  const verifyWebhookSignature = VerifyWebhookSignature;
2908
3069
  const toBase64 = ToBase64;
2909
3070
  const isApiKey = IsApiKey;
3071
+ const isAccessToken = IsAccessToken;
2910
3072
  const isSealed = IsSealed;
2911
3073
  const resolveLanguage = ResolveLanguage;
2912
3074
  const languageByCode = LanguageByCode;
2913
3075
  const isRtlLanguage = IsRtlLanguage;
2914
3076
 
2915
- export { API_SCOPES, AUDIENCE_MEMBER_STATUSES, BROADCAST_RECIPIENT_FILTERS, BROADCAST_STATUSES, CONTACT_BLOCK_LISTS, CONTACT_PHOTO_TYPES, CONTACT_THREAD_SORTS, DOMAIN_DMARC_STAGES, DOMAIN_RECORD_STATUSES, ERROR_TYPES, FILE_DIRECTIONS, FILE_KINDS, FILE_SORTS, FILE_USAGES, FILE_VISIBILITIES, LANGUAGES, MESSAGE_ENCRYPTION_FORMATS, OpenEmail, OpenEmailApiError, OpenEmailNetworkError, PAGE_LIMITS, PEOPLE_SORTS, PROVIDER_IMPORT_DOMAIN_STATES, PROVIDER_IMPORT_RESOURCES, PROVIDER_IMPORT_STATUSES, RULE_ACTIONS, RULE_FIELDS, RULE_OPERATORS, SUPPRESSION_REASONS, THREAD_SORTS, VERSION, WEBHOOK_EVENTS, WEBHOOK_REPLAY_ERROR_CODES, WEBHOOK_SIGNATURE_HEADERS, createClient, createOpenEmail, createTempMail, OpenEmail as default, getClient, init, isApiKey, isRtlLanguage, isSealed, languageByCode, openemail, resetClient, resolveLanguage, toBase64, verifyWebhookSignature };
3077
+ export { API_SCOPES, AUDIENCE_MEMBER_STATUSES, BROADCAST_RECIPIENT_FILTERS, BROADCAST_STATUSES, CONTACT_BLOCK_LISTS, CONTACT_PHOTO_TYPES, CONTACT_THREAD_SORTS, CREDENTIAL_KINDS, DOMAIN_DMARC_STAGES, DOMAIN_RECORD_STATUSES, ERROR_TYPES, FILE_DIRECTIONS, FILE_KINDS, FILE_SORTS, FILE_USAGES, FILE_VISIBILITIES, LANGUAGES, MESSAGE_ENCRYPTION_FORMATS, OpenEmail, OpenEmailApiError, OpenEmailNetworkError, PAGE_LIMITS, PEOPLE_SORTS, PROVIDER_IMPORT_DOMAIN_STATES, PROVIDER_IMPORT_RESOURCES, PROVIDER_IMPORT_STATUSES, RULE_ACTIONS, RULE_FIELDS, RULE_OPERATORS, STEP_UP_ERROR_CODES, STEP_UP_METHODS, SUPPRESSION_REASONS, THREAD_SORTS, VERSION, WEBHOOK_EVENTS, WEBHOOK_REPLAY_ERROR_CODES, WEBHOOK_SIGNATURE_HEADERS, createClient, createOpenEmail, createTempMail, OpenEmail as default, getClient, init, isAccessToken, isApiKey, isRtlLanguage, isSealed, languageByCode, openemail, resetClient, resolveLanguage, toBase64, verifyWebhookSignature };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openemail/sdk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "author": "OpenEmail",
5
5
  "license": "UNLICENSED",
6
6
  "description": "The official TypeScript SDK for the OpenEmail API. Send email and broadcasts, work with threads, drafts, labels, templates, rules, webhooks, tracking, contacts, audiences, domains, suppressions, files, API keys, roles, members, mailbox imports and disposable inboxes from code.",
@@ -39,7 +39,7 @@
39
39
  "sideEffects": false,
40
40
  "homepage": "https://openemail.uk/docs/sdk",
41
41
  "bugs": {
42
- "url": "https://openemail.uk/support"
42
+ "url": "https://openemail.uk/contact"
43
43
  },
44
44
  "keywords": [
45
45
  "openemail",