Skip to content

Commit 3eb5a8f

Browse files
author
Guy Bedford
authored
feat: fastly.sdkVersion implementation (#776)
1 parent 1ab46a3 commit 3eb5a8f

File tree

13 files changed

+126
-64
lines changed

13 files changed

+126
-64
lines changed

integration-tests/js-compute/fixtures/app/src/fastly-now.js renamed to integration-tests/js-compute/fixtures/app/src/fastly-global.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import { pass, assert } from "./assertions.js";
55
import { routes } from "./routes.js";
6+
import { sdkVersion } from "fastly:experimental";
67

78
routes.set("/fastly/now", function () {
89
let error = assert(typeof fastly.now, 'function', 'typeof fastly.now')
@@ -22,3 +23,13 @@ routes.set("/fastly/now", function () {
2223

2324
return pass()
2425
})
26+
27+
routes.set("/fastly/version", function () {
28+
let error = assert(typeof fastly.sdkVersion, 'string', 'typeof fastly.sdkVersion')
29+
if (error) { return error }
30+
31+
error = assert(fastly.sdkVersion, sdkVersion, 'fastly.sdkVersion matches fastly:experimental#sdkVersion')
32+
if (error) { return error }
33+
34+
return pass()
35+
})

integration-tests/js-compute/fixtures/app/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import "./dynamic-backend.js"
2222
import "./edge-rate-limiter.js"
2323
import "./env.js"
2424
import "./fanout.js"
25-
import "./fastly-now.js"
25+
import "./fastly-global.js"
2626
import "./fetch-errors.js"
2727
import "./geoip.js"
2828
import "./headers.js"

integration-tests/js-compute/fixtures/app/tests-starlingmonkey.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
"GET /backend/health/happy-path-backend-exists",
178178
"GET /backend/health/happy-path-backend-does-not-exist",
179179
"GET /env",
180+
"GET /fastly/version",
180181
"GET /multiple-set-cookie/response-init",
181182
"GET /multiple-set-cookie/response-direct",
182183
"GET /request/clone/called-as-constructor",

integration-tests/js-compute/fixtures/app/tests.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3058,6 +3058,16 @@
30583058
"status": 200
30593059
}
30603060
},
3061+
"GET /fastly/version": {
3062+
"environments": ["compute", "viceroy"],
3063+
"downstream_request": {
3064+
"method": "GET",
3065+
"pathname": "/fastly/version"
3066+
},
3067+
"downstream_response": {
3068+
"status": 200
3069+
}
3070+
},
30613071
"GET /fastly/getgeolocationforipaddress/interface": {
30623072
"environments": ["compute"],
30633073
"downstream_request": {

integration-tests/js-compute/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ if (!local) {
9191
const setupPath = join(fixturePath, 'setup.js')
9292
if (existsSync(setupPath)) {
9393
core.startGroup('Extra set-up steps for the service')
94-
await zx`${setupPath}`
94+
await zx`${setupPath}${starlingmonkey ? ' --starlingmonkey' : ''}`
9595
await sleep(60)
9696
core.endGroup()
9797
}

runtime/fastly/builtins/fastly.cpp

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ const JSErrorFormatString *FastlyGetErrorMessage(void *userRef, unsigned errorNu
3333

3434
namespace {
3535

36-
api::Engine *ENGINE;
37-
3836
bool enableDebugLogging(JSContext *cx, unsigned argc, JS::Value *vp) {
3937
JS::CallArgs args = CallArgsFromVp(argc, vp);
4038
if (!args.requireAtLeast(cx, __func__, 1))
@@ -51,6 +49,13 @@ JS::PersistentRooted<JSObject *> Fastly::baseURL;
5149
JS::PersistentRooted<JSString *> Fastly::defaultBackend;
5250
bool Fastly::allowDynamicBackends = false;
5351

52+
bool Fastly::version_get(JSContext *cx, unsigned argc, JS::Value *vp) {
53+
JS::CallArgs args = CallArgsFromVp(argc, vp);
54+
JS::RootedString version_str(cx, JS_NewStringCopyN(cx, RUNTIME_VERSION, strlen(RUNTIME_VERSION)));
55+
args.rval().setString(version_str);
56+
return true;
57+
}
58+
5459
bool Env::env_get(JSContext *cx, unsigned argc, JS::Value *vp) {
5560
JS::CallArgs args = CallArgsFromVp(argc, vp);
5661
if (!args.requireAtLeast(cx, "fastly.env.get", 1))
@@ -306,145 +311,151 @@ const JSPropertySpec Fastly::properties[] = {
306311
JS_PSGS("defaultBackend", defaultBackend_get, defaultBackend_set, JSPROP_ENUMERATE),
307312
JS_PSGS("allowDynamicBackends", allowDynamicBackends_get, allowDynamicBackends_set,
308313
JSPROP_ENUMERATE),
314+
JS_PSG("sdkVersion", version_get, JSPROP_ENUMERATE),
309315
JS_PS_END};
310316

311317
bool install(api::Engine *engine) {
312-
ENGINE = engine;
313-
JS::RootedObject fastly(ENGINE->cx(), JS_NewPlainObject(ENGINE->cx()));
318+
JS::RootedObject fastly(engine->cx(), JS_NewPlainObject(engine->cx()));
314319
if (!fastly) {
315320
return false;
316321
}
317322

318-
Fastly::env.init(ENGINE->cx(), Env::create(ENGINE->cx()));
323+
Fastly::env.init(engine->cx(), Env::create(engine->cx()));
319324
if (!Fastly::env) {
320325
return false;
321326
}
322327

323-
Fastly::baseURL.init(ENGINE->cx());
324-
Fastly::defaultBackend.init(ENGINE->cx());
328+
Fastly::baseURL.init(engine->cx());
329+
Fastly::defaultBackend.init(engine->cx());
325330

326-
if (!JS_DefineProperty(ENGINE->cx(), ENGINE->global(), "fastly", fastly, 0)) {
331+
if (!JS_DefineProperty(engine->cx(), engine->global(), "fastly", fastly, 0)) {
327332
return false;
328333
}
329334

330335
// fastly:env
331-
RootedValue env_get(ENGINE->cx());
332-
if (!JS_GetProperty(ENGINE->cx(), Fastly::env, "get", &env_get)) {
336+
RootedValue env_get(engine->cx());
337+
if (!JS_GetProperty(engine->cx(), Fastly::env, "get", &env_get)) {
333338
return false;
334339
}
335-
RootedObject env_builtin(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
336-
if (!JS_SetProperty(ENGINE->cx(), env_builtin, "env", env_get)) {
340+
RootedObject env_builtin(engine->cx(), JS_NewObject(engine->cx(), nullptr));
341+
if (!JS_SetProperty(engine->cx(), env_builtin, "env", env_get)) {
337342
return false;
338343
}
339-
RootedValue env_builtin_val(ENGINE->cx(), JS::ObjectValue(*env_builtin));
340-
if (!ENGINE->define_builtin_module("fastly:env", env_builtin_val)) {
344+
RootedValue env_builtin_val(engine->cx(), JS::ObjectValue(*env_builtin));
345+
if (!engine->define_builtin_module("fastly:env", env_builtin_val)) {
341346
return false;
342347
}
343348

344349
// fastly:experimental
345-
RootedObject experimental(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
346-
RootedValue experimental_val(ENGINE->cx(), JS::ObjectValue(*experimental));
350+
RootedObject experimental(engine->cx(), JS_NewObject(engine->cx(), nullptr));
351+
RootedValue experimental_val(engine->cx(), JS::ObjectValue(*experimental));
347352
// TODO(GB): implement includeBytes
348-
if (!JS_SetProperty(ENGINE->cx(), experimental, "includeBytes", experimental_val)) {
353+
if (!JS_SetProperty(engine->cx(), experimental, "includeBytes", experimental_val)) {
349354
return false;
350355
}
351356
auto set_default_backend =
352-
JS_NewFunction(ENGINE->cx(), &Fastly::defaultBackend_set, 1, 0, "setDefaultBackend");
353-
RootedObject set_default_backend_obj(ENGINE->cx(), JS_GetFunctionObject(set_default_backend));
354-
RootedValue set_default_backend_val(ENGINE->cx(), ObjectValue(*set_default_backend_obj));
355-
if (!JS_SetProperty(ENGINE->cx(), experimental, "setDefaultBackend", set_default_backend_val)) {
357+
JS_NewFunction(engine->cx(), &Fastly::defaultBackend_set, 1, 0, "setDefaultBackend");
358+
RootedObject set_default_backend_obj(engine->cx(), JS_GetFunctionObject(set_default_backend));
359+
RootedValue set_default_backend_val(engine->cx(), ObjectValue(*set_default_backend_obj));
360+
if (!JS_SetProperty(engine->cx(), experimental, "setDefaultBackend", set_default_backend_val)) {
356361
return false;
357362
}
358363
auto allow_dynamic_backends =
359-
JS_NewFunction(ENGINE->cx(), &Fastly::allowDynamicBackends_set, 1, 0, "allowDynamicBackends");
360-
RootedObject allow_dynamic_backends_obj(ENGINE->cx(),
364+
JS_NewFunction(engine->cx(), &Fastly::allowDynamicBackends_set, 1, 0, "allowDynamicBackends");
365+
RootedObject allow_dynamic_backends_obj(engine->cx(),
361366
JS_GetFunctionObject(allow_dynamic_backends));
362-
RootedValue allow_dynamic_backends_val(ENGINE->cx(), ObjectValue(*allow_dynamic_backends_obj));
363-
if (!JS_SetProperty(ENGINE->cx(), experimental, "allowDynamicBackends",
367+
RootedValue allow_dynamic_backends_val(engine->cx(), ObjectValue(*allow_dynamic_backends_obj));
368+
if (!JS_SetProperty(engine->cx(), experimental, "allowDynamicBackends",
364369
allow_dynamic_backends_val)) {
365370
return false;
366371
}
367-
if (!ENGINE->define_builtin_module("fastly:experimental", experimental_val)) {
372+
RootedString version_str(
373+
engine->cx(), JS_NewStringCopyN(engine->cx(), RUNTIME_VERSION, strlen(RUNTIME_VERSION)));
374+
RootedValue version_str_val(engine->cx(), StringValue(version_str));
375+
if (!JS_SetProperty(engine->cx(), experimental, "sdkVersion", version_str_val)) {
376+
return false;
377+
}
378+
if (!engine->define_builtin_module("fastly:experimental", experimental_val)) {
368379
return false;
369380
}
370381

371382
// TODO(GB): all of the following builtin modules are just placeholder shapes for now
372-
if (!ENGINE->define_builtin_module("fastly:body", env_builtin_val)) {
383+
if (!engine->define_builtin_module("fastly:body", env_builtin_val)) {
373384
return false;
374385
}
375-
RootedObject cache(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
376-
RootedValue cache_val(ENGINE->cx(), JS::ObjectValue(*cache));
377-
if (!JS_SetProperty(ENGINE->cx(), cache, "CoreCache", cache_val)) {
386+
RootedObject cache(engine->cx(), JS_NewObject(engine->cx(), nullptr));
387+
RootedValue cache_val(engine->cx(), JS::ObjectValue(*cache));
388+
if (!JS_SetProperty(engine->cx(), cache, "CoreCache", cache_val)) {
378389
return false;
379390
}
380-
if (!JS_SetProperty(ENGINE->cx(), cache, "CacheEntry", cache_val)) {
391+
if (!JS_SetProperty(engine->cx(), cache, "CacheEntry", cache_val)) {
381392
return false;
382393
}
383-
if (!JS_SetProperty(ENGINE->cx(), cache, "CacheEntry", cache_val)) {
394+
if (!JS_SetProperty(engine->cx(), cache, "CacheEntry", cache_val)) {
384395
return false;
385396
}
386-
if (!JS_SetProperty(ENGINE->cx(), cache, "SimpleCache", cache_val)) {
397+
if (!JS_SetProperty(engine->cx(), cache, "SimpleCache", cache_val)) {
387398
return false;
388399
}
389-
if (!ENGINE->define_builtin_module("fastly:cache", cache_val)) {
400+
if (!engine->define_builtin_module("fastly:cache", cache_val)) {
390401
return false;
391402
}
392-
if (!ENGINE->define_builtin_module("fastly:config-store", env_builtin_val)) {
403+
if (!engine->define_builtin_module("fastly:config-store", env_builtin_val)) {
393404
return false;
394405
}
395-
RootedObject device_device(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
396-
RootedValue device_device_val(ENGINE->cx(), JS::ObjectValue(*device_device));
397-
if (!JS_SetProperty(ENGINE->cx(), device_device, "Device", device_device_val)) {
406+
RootedObject device_device(engine->cx(), JS_NewObject(engine->cx(), nullptr));
407+
RootedValue device_device_val(engine->cx(), JS::ObjectValue(*device_device));
408+
if (!JS_SetProperty(engine->cx(), device_device, "Device", device_device_val)) {
398409
return false;
399410
}
400-
if (!ENGINE->define_builtin_module("fastly:device", device_device_val)) {
411+
if (!engine->define_builtin_module("fastly:device", device_device_val)) {
401412
return false;
402413
}
403-
RootedObject dictionary(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
404-
RootedValue dictionary_val(ENGINE->cx(), JS::ObjectValue(*dictionary));
405-
if (!JS_SetProperty(ENGINE->cx(), dictionary, "Dictionary", dictionary_val)) {
414+
RootedObject dictionary(engine->cx(), JS_NewObject(engine->cx(), nullptr));
415+
RootedValue dictionary_val(engine->cx(), JS::ObjectValue(*dictionary));
416+
if (!JS_SetProperty(engine->cx(), dictionary, "Dictionary", dictionary_val)) {
406417
return false;
407418
}
408-
if (!ENGINE->define_builtin_module("fastly:dictionary", dictionary_val)) {
419+
if (!engine->define_builtin_module("fastly:dictionary", dictionary_val)) {
409420
return false;
410421
}
411-
RootedObject edge_rate_limiter(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
412-
RootedValue edge_rate_limiter_val(ENGINE->cx(), JS::ObjectValue(*edge_rate_limiter));
413-
if (!JS_SetProperty(ENGINE->cx(), edge_rate_limiter, "RateCounter", edge_rate_limiter_val)) {
422+
RootedObject edge_rate_limiter(engine->cx(), JS_NewObject(engine->cx(), nullptr));
423+
RootedValue edge_rate_limiter_val(engine->cx(), JS::ObjectValue(*edge_rate_limiter));
424+
if (!JS_SetProperty(engine->cx(), edge_rate_limiter, "RateCounter", edge_rate_limiter_val)) {
414425
return false;
415426
}
416-
if (!JS_SetProperty(ENGINE->cx(), edge_rate_limiter, "PenaltyBox", edge_rate_limiter_val)) {
427+
if (!JS_SetProperty(engine->cx(), edge_rate_limiter, "PenaltyBox", edge_rate_limiter_val)) {
417428
return false;
418429
}
419-
if (!JS_SetProperty(ENGINE->cx(), edge_rate_limiter, "EdgeRateLimiter", edge_rate_limiter_val)) {
430+
if (!JS_SetProperty(engine->cx(), edge_rate_limiter, "EdgeRateLimiter", edge_rate_limiter_val)) {
420431
return false;
421432
}
422-
if (!ENGINE->define_builtin_module("fastly:edge-rate-limiter", edge_rate_limiter_val)) {
433+
if (!engine->define_builtin_module("fastly:edge-rate-limiter", edge_rate_limiter_val)) {
423434
return false;
424435
}
425-
RootedObject fanout(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
426-
RootedValue fanout_val(ENGINE->cx(), JS::ObjectValue(*fanout));
427-
if (!JS_SetProperty(ENGINE->cx(), fanout, "createFanoutHandoff", fanout_val)) {
436+
RootedObject fanout(engine->cx(), JS_NewObject(engine->cx(), nullptr));
437+
RootedValue fanout_val(engine->cx(), JS::ObjectValue(*fanout));
438+
if (!JS_SetProperty(engine->cx(), fanout, "createFanoutHandoff", fanout_val)) {
428439
return false;
429440
}
430-
if (!ENGINE->define_builtin_module("fastly:fanout", fanout_val)) {
441+
if (!engine->define_builtin_module("fastly:fanout", fanout_val)) {
431442
return false;
432443
}
433-
if (!ENGINE->define_builtin_module("fastly:geolocation", env_builtin_val)) {
444+
if (!engine->define_builtin_module("fastly:geolocation", env_builtin_val)) {
434445
return false;
435446
}
436-
RootedObject kv_store(ENGINE->cx(), JS_NewObject(ENGINE->cx(), nullptr));
437-
RootedValue kv_store_val(ENGINE->cx(), JS::ObjectValue(*kv_store));
438-
if (!JS_SetProperty(ENGINE->cx(), kv_store, "KVStore", kv_store_val)) {
447+
RootedObject kv_store(engine->cx(), JS_NewObject(engine->cx(), nullptr));
448+
RootedValue kv_store_val(engine->cx(), JS::ObjectValue(*kv_store));
449+
if (!JS_SetProperty(engine->cx(), kv_store, "KVStore", kv_store_val)) {
439450
return false;
440451
}
441-
if (!ENGINE->define_builtin_module("fastly:kv-store", kv_store_val)) {
452+
if (!engine->define_builtin_module("fastly:kv-store", kv_store_val)) {
442453
return false;
443454
}
444-
if (!ENGINE->define_builtin_module("fastly:logger", env_builtin_val)) {
455+
if (!engine->define_builtin_module("fastly:logger", env_builtin_val)) {
445456
return false;
446457
}
447-
if (!ENGINE->define_builtin_module("fastly:secret-store", env_builtin_val)) {
458+
if (!engine->define_builtin_module("fastly:secret-store", env_builtin_val)) {
448459
return false;
449460
}
450461

@@ -463,8 +474,8 @@ bool install(api::Engine *engine) {
463474
// options.getExperimentalHighResolutionTimeMethodsEnabled() ? nowfn : end,
464475
end};
465476

466-
return JS_DefineFunctions(ENGINE->cx(), fastly, methods) &&
467-
JS_DefineProperties(ENGINE->cx(), fastly, Fastly::properties);
477+
return JS_DefineFunctions(engine->cx(), fastly, methods) &&
478+
JS_DefineProperties(engine->cx(), fastly, Fastly::properties);
468479
}
469480

470481
} // namespace fastly::fastly

runtime/fastly/builtins/fastly.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ using namespace builtins;
1313

1414
namespace fastly::fastly {
1515

16+
#define RUNTIME_VERSION "starlingmonkey-dev"
17+
1618
class Env : public BuiltinNoConstructor<Env> {
1719
private:
1820
static bool env_get(JSContext *cx, unsigned argc, JS::Value *vp);
@@ -53,6 +55,7 @@ class Fastly : public BuiltinNoConstructor<Fastly> {
5355
// static bool getGeolocationForIpAddress(JSContext *cx, unsigned argc, JS::Value *vp);
5456
// static bool getLogger(JSContext *cx, unsigned argc, JS::Value *vp);
5557
// static bool includeBytes(JSContext *cx, unsigned argc, JS::Value *vp);
58+
static bool version_get(JSContext *cx, unsigned argc, JS::Value *vp);
5659
static bool env_get(JSContext *cx, unsigned argc, JS::Value *vp);
5760
static bool baseURL_get(JSContext *cx, unsigned argc, JS::Value *vp);
5861
static bool baseURL_set(JSContext *cx, unsigned argc, JS::Value *vp);

runtime/js-compute-runtime/builtins/fastly.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ bool Fastly::env_get(JSContext *cx, unsigned argc, JS::Value *vp) {
204204
return true;
205205
}
206206

207+
bool Fastly::version_get(JSContext *cx, unsigned argc, JS::Value *vp) {
208+
JS::CallArgs args = CallArgsFromVp(argc, vp);
209+
JS::RootedString version_str(cx, JS_NewStringCopyN(cx, RUNTIME_VERSION, strlen(RUNTIME_VERSION)));
210+
args.rval().setString(version_str);
211+
return true;
212+
}
213+
207214
bool Fastly::baseURL_get(JSContext *cx, unsigned argc, JS::Value *vp) {
208215
JS::CallArgs args = CallArgsFromVp(argc, vp);
209216
args.rval().setObjectOrNull(baseURL);
@@ -262,6 +269,7 @@ const JSPropertySpec Fastly::properties[] = {
262269
JS_PSGS("defaultBackend", defaultBackend_get, defaultBackend_set, JSPROP_ENUMERATE),
263270
JS_PSGS("allowDynamicBackends", allowDynamicBackends_get, allowDynamicBackends_set,
264271
JSPROP_ENUMERATE),
272+
JS_PSG("sdkVersion", version_get, JSPROP_ENUMERATE),
265273
JS_PS_END};
266274

267275
bool Fastly::create(JSContext *cx, JS::HandleObject global, FastlyOptions options) {

runtime/js-compute-runtime/builtins/fastly.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Fastly : public BuiltinNoConstructor<Fastly> {
3131
static bool getLogger(JSContext *cx, unsigned argc, JS::Value *vp);
3232
static bool includeBytes(JSContext *cx, unsigned argc, JS::Value *vp);
3333
static bool env_get(JSContext *cx, unsigned argc, JS::Value *vp);
34+
static bool version_get(JSContext *cx, unsigned argc, JS::Value *vp);
3435
static bool baseURL_get(JSContext *cx, unsigned argc, JS::Value *vp);
3536
static bool baseURL_set(JSContext *cx, unsigned argc, JS::Value *vp);
3637
static bool defaultBackend_get(JSContext *cx, unsigned argc, JS::Value *vp);

runtime/js-compute-runtime/js-compute-builtins.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ const JSErrorFormatString js_ErrorFormatString[JSErrNum_Limit] = {
3232

3333
#include "host_interface/host_api.h"
3434

35+
#define RUNTIME_VERSION "3.13.2-dev"
36+
3537
const JSErrorFormatString *GetErrorMessage(void *userRef, unsigned errorNumber);
3638

3739
JSObject *PromiseRejectedWithPendingError(JSContext *cx);

src/bundle.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export const enableDebugLogging = globalThis.fastly.enableDebugLogging;
3535
export const setBaseURL = Object.getOwnPropertyDescriptor(globalThis.fastly, 'baseURL').set;
3636
export const setDefaultBackend = Object.getOwnPropertyDescriptor(globalThis.fastly, 'defaultBackend').set;
3737
export const allowDynamicBackends = Object.getOwnPropertyDescriptor(globalThis.fastly, 'allowDynamicBackends').set;
38+
export const sdkVersion = globalThis.fastly.sdkVersion;
3839
`
3940
}
4041
}

types/experimental.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
* @experimental
55
*/
66
declare module "fastly:experimental" {
7+
/**
8+
* JavaScript SDK version string for the JS runtime engine build.
9+
*
10+
* @experimental
11+
* @hidden
12+
*/
13+
export const sdkVersion: string;
714
/**
815
* @experimental
916
* @hidden

0 commit comments

Comments
 (0)