{"id":20874977,"url":"https://github.com/servicestack/servicestack-client","last_synced_at":"2025-04-06T07:12:22.363Z","repository":{"id":9431775,"uuid":"62095374","full_name":"ServiceStack/servicestack-client","owner":"ServiceStack","description":"ServiceStack Service Client, Server Events and validation library","archived":false,"fork":false,"pushed_at":"2025-02-05T14:22:29.000Z","size":1221,"stargazers_count":21,"open_issues_count":0,"forks_count":20,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-30T06:07:36.122Z","etag":null,"topics":["authentication","generic","javascript","service-client","servicestack","typed","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ServiceStack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-27T23:34:57.000Z","updated_at":"2025-02-05T14:22:32.000Z","dependencies_parsed_at":"2023-01-13T15:21:11.475Z","dependency_job_id":"92f60139-285d-4517-96fa-af731426a80e","html_url":"https://github.com/ServiceStack/servicestack-client","commit_stats":{"total_commits":429,"total_committers":5,"mean_commits":85.8,"dds":0.07692307692307687,"last_synced_commit":"5ec5bfa451519347068a3560dd486a06ac2d3a77"},"previous_names":[],"tags_count":148,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2Fservicestack-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2Fservicestack-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2Fservicestack-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ServiceStack%2Fservicestack-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ServiceStack","download_url":"https://codeload.github.com/ServiceStack/servicestack-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247445671,"owners_count":20939958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","generic","javascript","service-client","servicestack","typed","typescript"],"created_at":"2024-11-18T06:40:36.517Z","updated_at":"2025-04-06T07:12:22.340Z","avatar_url":"https://github.com/ServiceStack.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @servicestack/client\n\nThe **@servicestack/client** library enables the best end-to-end typed developer experience for calling [ServiceStack APIs](https://servicestack.net/) in any TypeScript or JavaScript project.\n\n### v2.x Changes\n\n - Switched to use `/api` pre-defined route by default, revert to legacy `/json/reply` pre-defined route with:\n\n```ts\nconst client = new JsonServiceClient(baseUrl).useBasePath()\n```\n\n - **@servicestack/client** now dependency-free\n\nAs [fetch is available in Node.js v18+ LTS](https://blog.logrocket.com/fetch-api-node-js/) all polyfills have been removed to make **@servicestack/client** dependency-free in its latest major **v2.x** version.\n\nThis should have no effect when using [JsonServiceClient](https://docs.servicestack.net/javascript-client) in Browsers which uses its native `fetch()` or from Node.js v18+ that now has native `fetch` support. \n\n#### ServerEventsClient in Node.js\n\nNode.js projects using [ServerEventsClient](https://docs.servicestack.net/typescript-server-events-client) (e.g. in tests) now require a polyfill:\n\n```bash\n$ npm install eventsource\n```\n\nThen polyfill with:\n\n```ts\nglobalThis.EventSource = require(\"eventsource\")\n```\n\n#### JsonServiceClient in Node.js \u003c v18\n\nOlder Node.js runtimes using `JsonServiceClient` can continue using the existing **v1.x** version or polyfill `fetch` with:\n\n```bash\n$ npm install cross-fetch\n```\n\nThen polyfill with:\n\n```js\nrequire('cross-fetch/polyfill')\n```\n\n## Usage in ServiceStack Projects\n\nAll ServiceStack Project Templates are pre-configured to use **@servicestack/client**, they can be created from:\n\n### [https://servicestack.net/start](https://servicestack.net/start)\n\n## Usage in TypeScript or npm projects\n\nProjects using TypeScript or any npm build system can install the dependency-free library with:\n\n```bash\nnpm install @servicestack/client\n```\n\nWhich can be used with your APIs typed DTOs that TypeScript projects can generate using \n[TypeScript Add ServiceStack Reference](https://docs.servicestack.net/typescript-add-servicestack-reference#typescript-serviceclient) with:\n\n```bash\nx ts https://localhost:5001\n```\n\nWhich will save your API DTOs to **dtos.ts** that can be referenced in your code with:\n\n```ts\nimport { Hello } from \"./dtos\"\n```\n\n### JavaScript npm projects\n\nNon-TypeScript npm projects can choose to have TypeScript generate the DTOs into the preferred JavaScript target:\n\n```bash\ntsc dtos.ts \n```\n\nAlternatively they can generate ES6 annotated DTOs using [JavaScript Add ServiceStack Reference](https://docs.servicestack.net/javascript-add-servicestack-reference) with:\n\n```bash\nx mjs https://localhost:5001\n```\n\nWhich will save your API DTOs to **dtos.mjs** where they can be referenced in your code with:\n\n```ts\nimport { Hello } from \"./dtos.mjs\"\n```\n\n### Example Usage\n\nEither solution gives you the same productive end-to-end Typed API access, e.g:\n\n```ts\nimport { JsonApiClient } from \"@servicestack/client\"\n\nconst client = JsonApiClient.create(baseUrl)\n\nconst api = await client.api(new Hello({ Name: 'World' }))\nif (api.succeeded) {\n    console.log(api.response.result)\n} else {\n    console.log(api.error)\n}\n```\n\n## Usage in .NET Apps without npm\n\nModern JavaScript Apps not using an npm build system like the [Razor Vue Tailwind templates](https://docs.servicestack.net/vue/#getting-started) can download \n**@servicestack/client** from:\n\n - https://unpkg.com/@servicestack/client@2/dist/servicestack-client.mjs\n - https://unpkg.com/@servicestack/client@2/dist/servicestack-client.min.mjs (minified)\n\nThen use an [importmap](https://docs.servicestack.net/javascript-add-servicestack-reference#import-maps) to specify where to load **@servicestack/client** from, e.g:\n\n```html\n\u003c!-- polyfill for safari --\u003e\n\u003cscript async src=\"https://ga.jspm.io/npm:es-module-shims@1.6.3/dist/es-module-shims.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"importmap\"\u003e\n{\n    \"imports\": {\n        \"@servicestack/client\": \"/js/servicestack-client.mjs\"\n    }\n}\n\u003c/script\u003e\n```\n\n### ImportMap in Razor Pages or MVC\n\nRazor Pages or MVC projects can use `@Html.ImportMap()` in **_Layout.cshtml** to use different builds for development and production, e.g:\n\n```csharp\n@if (Context.Request.Headers.UserAgent.Any(x =\u003e x.Contains(\"Safari\") \u0026\u0026 !x.Contains(\"Chrome\")))\n{\n    \u003cscript async src=\"https://ga.jspm.io/npm:es-module-shims@1.6.3/dist/es-module-shims.js\"\u003e\u003c/script\u003e\n}\n@Html.ImportMap(new()\n{\n    [\"@servicestack/client\"] = (\"/js/servicestack-client.mjs\", \"/js/servicestack-client.min.mjs\"),\n})\n```\n\nThis lets your source code reference the library by package name to enable using the same source code in a \n[JavaScript Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), e.g:\n\n```html\n\u003cscript type=\"module\"\u003e\nimport { JsonApiClient } from \"@servicestack/client\"\n\nconst client = JsonApiClient.create(baseUrl)\n\nconst api = await client.api(new Hello({ Name: 'World' }))\n\u003c/script\u003e\n```\n\n### JavaScript API DTOs\n\nYour [JavaScript API DTOs](https://docs.servicestack.net/javascript-add-servicestack-reference) can either directly reference the **/types/mjs** endpoint:\n\n```js\nimport { Hello } from '/types/mjs'\n```\n\n### Enable static analysis and intelli-sense \n\nOr for better IDE intelli-sense during development, save the annotated Typed DTOs to disk with the [x dotnet tool](https://docs.servicestack.net/dotnet-tool):\n\n```sh\nx mjs\n```\n\nThen reference it instead to enable IDE static analysis when calling Typed APIs from JavaScript:\n\n```js\nimport { Hello } from '/js/dtos.mjs'\nclient.api(new Hello({ name }))\n```\n    \nTo also enable static analysis for **@servicestack/client**, install the dependency-free library as a dev dependency:\n    \n```sh\nnpm install -D @servicestack/client\n```\n\nWhere only its TypeScript definitions are used by the IDE during development to enable its type-checking and intelli-sense.\n\n#### Support Legacy Browsers\n\nJavaScript Projects needing to support legacy browsers can use [ES3 Common.js DTOs](https://docs.servicestack.net/commonjs-add-servicestack-reference) to \nenable access using old-style `\u003cscript\u003e` includes.\n\n## JsonServiceClient\n\nTo create `JsonServiceClient` instances in v6+ projects using the [JSON /api route](https://docs.servicestack.net/routing#json-api-pre-defined-route) use:\n\n```js\nconst client = JsonApiClient.create(baseUrl)\n```\n\nWhere it's configured to not use any JSON HTTP Headers to enable more efficient CORS requests without preflight requests.\n\nAlternatively all other projects can use the default constructor:\n\n```js\nconst client = new JsonServiceClient(baseUrl)\n```\n\n### API Reference\n\n[![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/clients/JsonServiceClient-ui-reference.png)](https://api.locode.dev/classes/client.JsonServiceClient.html)\n\n### API method\n\nThe `api` returns a typed `ApiResult\u003cResponse\u003e` Value Result that encapsulates either a Typed Response or a \nstructured API Error populated in `ResponseStatus` allowing you to handle API responses programmatically without\n`try/catch` handling:\n\n```ts\nconst api = client.api(new Hello({ name }))\nif (api.failed) {\n    console.log(`Greeting failed! ${e.errorCode}: ${e.errorMessage}`);\n    return;\n}\n\nconsole.log(`API Says: ${api.response.result}`) //api.succeeded\n```\n\n### Simplified API Handling\n\nBeing able to treat errors as values greatly increases the ability to programmatically handle and genericize api handling\nand greatly simplifies functionality needing to handle both successful and error responses like binding to UI components.\n\nAn example of this is below where we're able to concurrently fire off multiple unrelated async requests in parallel, \nwait for them all to complete, print out the ones that have succeeded or failed then access their strong typed responses: \n\n```ts\nimport { JsonServiceClient } from \"@servicestack/client\"\n\nlet requests:ApiRequest[] = [\n    new AppOverview(),            // GET =\u003e AppOverviewResponse\n    new DeleteTechnology(),       // DELETE =\u003e IReturnVoid (requires auth) \n    new GetAllTechnologies(),     // GET =\u003e GetAllTechnologiesResponse\n    new GetAllTechnologyStacks(), // GET =\u003e GetAllTechnologyStacksResponse\n]\n\nlet results = await Promise.all(requests.map(async (request) =\u003e\n    ({ request, api:await client.api(request) as ApiResponse}) ))\n\nlet failed = results.filter(x =\u003e x.api.failed)\nconsole.log(`${failed.length} failed:`)\nfailed.forEach(x =\u003e\n    console.log(`    ${x.request.getTypeName()} Request Failed: ${failed.map(x =\u003e x.api.errorMessage)}`))\n\nlet succeeded = results.filter(x =\u003e x.api.succeeded)\nconsole.log(`\\n${succeeded.length} succeeded: ${succeeded.map(x =\u003e x.request.getTypeName()).join(', ')}`)\n\nlet r = succeeded.find(x =\u003e x.request.getTypeName() == 'AppOverview')?.api.response as AppOverviewResponse\nif (r) console.log(`Top 5 Technologies:${r.topTechnologies.slice(0,4).map(tech =\u003e tech.name).join(', ')}`)\n```\n\nOutput:\n\n```\n1 failed\nDeleteTechnology Request Failed: Unauthorized\n\n3 succeeded: AppOverview, GetAllTechnologies, GetAllTechnologyStacks\nTop 5 Technologies: Redis, MySQL, Amazon EC2, Nginx\n```\n\nBeing able to treat Errors as values has dramatically reduced the effort required to accomplish the same feat if needing \nto handle errors with `try/catch`.\n\n### Ideal Typed Message-based API\n\nThe TypeScript `JsonServiceClient` enables the same productive, typed API development experience available \nin ServiceStack's other [1st-class supported client platforms](https://docs.servicestack.net/typescript-add-servicestack-reference). \n\nThe `JsonServiceClient` leverages the additional type hints ServiceStack embeds in each TypeScript Request DTO \nto achieve the ideal typed, message-based API - so all API requests benefit from a succinct, boilerplate-free \nTyped API. \n\nHere's a quick look at what it looks like. The example below shows how to create a \n[C# Gist in Gistlyn](https://github.com/ServiceStack/Gistlyn) \nafter adding a [TypeScript ServiceStack Reference](https://docs.servicestack.net/typescript-add-servicestack-reference)\nto `gistlyn.com` and installing the [@servicestack/client](https://www.npmjs.com/package/@servicestack/client) \nnpm package: \n\n```ts\nimport { JsonServiceClient } from '@servicestack/client';\nimport { StoreGist, GithubFile } from './dtos';\n\nconst client = new JsonServiceClient(\"https://gistlyn.com\");\n\nconst request = new StoreGist({\n    files: { \n        [file.filename]: new GithubFile({\n            filename: 'main.cs',\n            content: 'var greeting = \"Hi, from TypeScript!\";' \n        }) \n    }\n})\n\nconst api = client.api(request); //response:StoreGistResponse\nif (api.succeeded) {\n    console.log(`New C# Gist was created with id: ${r.gist}`);\n    location.href = `https://gist.cafe/${r.gist}`;\n} else {\n    console.log(\"Failed to create Gist: \", e.errorMessage);\n}\n```\n\nWhere the `response` param is typed to `StoreGistResponse` DTO Type.\n\n### Sending additional arguments with Typed API Requests\n\nMany AutoQuery Services utilize \n[implicit conventions](https://docs.servicestack.net/autoquery-rdbms#implicit-conventions) \nto query fields that aren't explicitly defined on AutoQuery Request DTOs, these can now be queried by specifying additional arguments with the typed Request DTO, e.g:\n\n```ts\n//typed to QueryResponse\u003cTechnologyStack\u003e \nconst response = await client.get(new FindTechStacks(), { VendorName: \"ServiceStack\" });\n```\n\nWhich will [return TechStacks](http://techstacks.io/ss_admin/autoquery/FindTechStacks) developed by ServiceStack.\n\n### Calling APIs with Custom URLs\n\nYou can call Services using relative or absolute urls, e.g:\n\n```ts\nclient.get\u003cGetTechnologyResponse\u003e(\"/technology/ServiceStack\")\n\nclient.get\u003cGetTechnologyResponse\u003e(\"http://techstacks.io/technology/ServiceStack\")\n\n// GET http://techstacks.io/technology?Slug=ServiceStack\nclient.get\u003cGetTechnologyResponse\u003e(\"/technology\", { Slug: \"ServiceStack\" }) \n```\n\nas well as POST Request DTOs to custom urls:\n\n```ts\nclient.postToUrl(\"/custom-path\", request, { Slug: \"ServiceStack\" });\n\nclient.putToUrl(\"http://example.org/custom-path\", request);\n```\n\n### Raw Data Responses\n\nThe `JsonServiceClient` also supports Raw Data responses like `string` and `byte[]` which also get a Typed API \nonce declared on Request DTOs using the `IReturn\u003cT\u003e` marker:\n\n```csharp\npublic class ReturnString : IReturn\u003cstring\u003e {}\npublic class ReturnBytes : IReturn\u003cbyte[]\u003e {}\n```\n\nWhich can then be accessed as normal, with their Response typed to a JavaScript `string` or `Uint8Array` for \nraw `byte[]` responses:\n\n```ts\nlet str:string = await client.get(new ReturnString());\n\nlet data:Uint8Array = await client.get(new ReturnBytes());\n```\n\n### Authenticating using Basic Auth\n\nBasic Auth support is implemented in `JsonServiceClient` and follows the same API made available in the C# \nService Clients where the `userName/password` properties can be set individually, e.g:\n\n```ts\nvar client = new JsonServiceClient(baseUrl);\nclient.userName = user;\nclient.password = pass;\n\nconst response = await client.get(new SecureRequest());\n```\n\nOr use `client.setCredentials()` to have them set both together.\n\n### Authenticating using Credentials\n\nAlternatively you can authenticate using userName/password credentials by \n[adding a TypeScript Reference](https://docs.servicestack.net/typescript-add-servicestack-reference#add-typescript-reference) \nto your remote ServiceStack Instance and sending a populated `Authenticate` Request DTO, e.g:\n\n```ts\nconst response = await client.post(new Authenticate({\n    provider: \"credentials\", userName, password, rememberMe: true }));\n```\n\nThis will populate the `JsonServiceClient` with \n[Session Cookies](https://docs.servicestack.net/sessions#cookie-session-ids) \nwhich will transparently be sent on subsequent requests to make authenticated requests.\n\n### Authenticating using JWT\n\nUse the `bearerToken` property to Authenticate with a [ServiceStack JWT Provider](https://docs.servicestack.net/jwt-authprovider) using a JWT Token:\n\n```ts\nclient.bearerToken = jwtToken;\n```\n\nAlternatively you can use a [Refresh Token](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) instead:\n\n```ts\nclient.refreshToken = refreshToken;\n```\n\n### Authenticating using an API Key\n\nUse the `bearerToken` property to Authenticate with an [API Key](https://docs.servicestack.net/api-key-authprovider):\n\n```ts\nclient.bearerToken = apiKey;\n```\n\n### Transparently handle 401 Unauthorized Responses\n\nIf the server returns a 401 Unauthorized Response either because the client was Unauthenticated or the \nconfigured Bearer Token or API Key used had expired or was invalidated, you can use `onAuthenticationRequired`\ncallback to re-configure the client before automatically retrying the original request, e.g:\n\n```ts\nclient.onAuthenticationRequired = async () =\u003e {\n    const authClient = new JsonServiceClient(authBaseUrl);\n    authClient.userName = userName;\n    authClient.password = password;\n    const response = await authClient.get(new Authenticate());\n    client.bearerToken = response.bearerToken;\n};\n\n//Automatically retries requests returning 401 Responses with new bearerToken\nvar response = await client.get(new Secured());\n```\n\n### Automatically refresh Access Tokens\n\nWith the [Refresh Token support in JWT](https://docs.servicestack.net/jwt-authprovider#refresh-tokens) \nyou can use the `refreshToken` property to instruct the Service Client to automatically fetch new \nJWT Tokens behind the scenes before automatically retrying failed requests due to invalid or expired JWTs, e.g:\n\n```ts\n//Authenticate to get new Refresh Token\nconst authClient = new JsonServiceClient(authBaseUrl);\nauthClient.userName = userName;\nauthClient.password = password;\nconst authResponse = await authClient.get(new Authenticate());\n\n//Configure client with RefreshToken\nclient.refreshToken = authResponse.RefreshToken;\n\n//Call authenticated Services and clients will automatically retrieve new JWT Tokens as needed\nconst response = await client.get(new Secured());\n```\n\nUse the `refreshTokenUri` property when refresh tokens need to be sent to a different ServiceStack Server, e.g:\n\n```ts\nclient.refreshToken = refreshToken;\nclient.refreshTokenUri = authBaseUrl + \"/access-token\";\n```\n\n### [ServerEvents Client](https://docs.servicestack.net/typescript-server-events-client)\n\nThe [TypeScript ServerEventClient](https://docs.servicestack.net/typescript-server-events-client) \nis an idiomatic port of ServiceStack's \n[C# Server Events Client](https://docs.servicestack.net/csharp-server-events-client) \nin native TypeScript providing a productive client to consume ServiceStack's \n[real-time Server Events](https://docs.servicestack.net/server-events) that can be used in TypeScript \n[Web, Node.js Server and React Native iOS and Android Mobile Apps](https://github.com/ServiceStackApps/typescript-server-events).\n\n```ts\nconst channels = [\"home\"];\nconst client = new ServerEventsClient(\"/\", channels, {\n    handlers: {\n        onConnect: (sub:ServerEventConnect) =\u003e {  // Successful SSE connection\n            console.log(\"You've connected! welcome \" + sub.displayName);\n        },\n        onJoin: (msg:ServerEventJoin) =\u003e {        // User has joined subscribed channel\n            console.log(\"Welcome, \" + msg.displayName);\n        },\n        onLeave: (msg:ServerEventLeave) =\u003e {      // User has left subscribed channel\n            console.log(msg.displayName + \" has left the building\");\n        },\n        onUpdate: (msg:ServerEventUpdate) =\u003e {    // User channel subscription was changed\n            console.log(msg.displayName + \" channels subscription were updated\");\n        },        \n        onMessage: (msg:ServerEventMessage) =\u003e {},// Invoked for each other message\n        //... Register custom handlers\n        announce: (text:string) =\u003e {},            // Handle messages with simple argument\n        chat: (chatMsg:ChatMessage) =\u003e {},        // Handle messages with complex type argument\n        CustomMessage: (msg:CustomMessage) =\u003e {}, // Handle complex types with default selector\n    },\n    receivers: { \n        //... Register any receivers\n        tv: {\n            watch: function (id) {                // Handle 'tv.watch {url}' messages \n                var el = document.querySelector(\"#tv\");\n                if (id.indexOf('youtu.be') \u003e= 0) {\n                    var v = splitOnLast(id, '/')[1];\n                    el.innerHTML = templates.youtube.replace(\"{id}\", v);\n                } else {\n                    el.innerHTML = templates.generic.replace(\"{id}\", id);\n                }\n                el.style.display = 'block'; \n            },\n            off: function () {                    // Handle 'tv.off' messages\n                var el = document.querySelector(\"#tv\");\n                el.style.display = 'none';\n                el.innerHTML = '';\n            }\n        }\n    },\n    onException: (e:Error) =\u003e {},                 // Invoked on each Error\n    onReconnect: (e:Error) =\u003e {}                  // Invoked after each auto-reconnect\n})\n.addListener(\"theEvent\",(e:ServerEventMessage) =\u003e {}) // Add listener for pub/sub event trigger\n.start();                                             // Start listening for Server Events!\n```\n\nWhen publishing a DTO Type for your Server Events message, your clients will be able to benefit from the generated DTOs in [TypeScript ServiceStack References](https://docs.servicestack.net/typescript-add-servicestack-reference).\n\n## Rich intelli-sense support\n\nEven pure HTML/JS Apps that don't use TypeScript or any external dependencies will still benefit from the Server \ngenerated `dtos.ts` and TypeScript definitions where you'll be able to benefit from rich intelli-sense support \nin smart IDEs like [Rider](https://www.jetbrains.com/rider/) for both the client library:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/mix/init-rider-ts-client.png)\n\nAs well as your App's server generated DTOs:\n\n![](https://raw.githubusercontent.com/ServiceStack/docs/master/docs/images/release-notes/v6.6/mjs-intellisense.png)\n\nSo even simple Apps without complex bundling solutions or external dependencies can still benefit from a rich typed authoring \nexperience without any additional build time or tooling complexity.\n\n## Feedback and Support\n\nSupport is available from the ServiceStack [Customer Forums](https://forums.servicestack.net) or [GitHub Discussions](https://servicestack.net/ask).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fservicestack%2Fservicestack-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fservicestack%2Fservicestack-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fservicestack%2Fservicestack-client/lists"}