You would benefit from using a streaming subscription. If you use a live query, you have to manually maintain a "cursor" (ie last message you fetched) and update your graphql subscription accordingly every time a new message is received or sent. If you don't you'll be refetching the same messages repeatedly, and they'll just grow as more messages are added.
With a streaming subscription this is all taken care of, you simply do something like this:
1) Load the last 50 messages (or whatever number of existing messages suits you)
2) Run your streaming subscription using the most recent of the messages from above as you cursor
3) When you send a message, do nothing and let the subscription handle getting the message you just sent
I built an ERP-like application for a small production company entirely with Airtable as the backend, but wrapped in a GraphQL schema. The Airtable app fetches the schema of a base when you load it, complete with all type columns, data types, select options, lookup ids, etc. You can use that to generate a GraphQL schema and fetch the data from Airtable in your resolvers. The rate-limiting and general speed when fetching a lot of data makes it unsuited for things that need to scale, but having the excellent Airtable UI for raw data entry and a custom application for everything else (complex data entry, reporting, kpis and such) was very nice.
That said, if I were to do it again today I'd probably go with Hasura or something more suited as an actual backend.
Beyond a certain size and complexity (which is not that much), I find that the argument of typescript (and other typed languages) being less productive than untyped dynamic ones, is not true when you look at it as a whole. It might feel slower, especially to begin with, but once you get used to the language and semantics you save a vast amount of time, by the bugs you _don't_ debug and by not having to jump through the code all the time to find out what that function or module was called or what parameters it accepted. This of course is less true if you're using a lot of untyped packages, but as you said, most do have types either natively or in the DefinitelyTyped project. For most modules it's also feasible to declare the module typings manually, even doing it gradually for the parts that you happen to need at a given time.
An alternative to this and Apollo codegen is GraphQL Code Generator[1]. Like codegen it takes the opposite approach by generating typescript from graphql. It's similar to codegen, with the main two differences being 1) it's not centered around queries, it will generate types for all schema parts as well as queries defined client-side. This is useful for getting typescript types for all the individual schema parts without being "wrapped" in the type of a query, and 2) it's template based and relatively easy to extend modify how the code is generated.
We use graphql-code-generator to make Typescript. We also upload versions of our typescript-query files (written separately from other client TS code) for each published version/branch (e.g. 1.1, 1.2, dev) and then can use an eslint plugin on the graphql server to validate it doesn't break backwards compatibility with existing client-side code (unless intentional). This has definitely saved us more than once.
I learned a lot from the SQLite documentation. It's not only very thorough, but it's full of insightful bits of information that is not strictly necessary but which gives a deeper understanding of the engine.
It was also the first time I encountered the flow diagram type of syntax explanation which I found to be a fantastic way to grasp the details of each command. Eg https://sqlite.org/lang_createtable.html.
With a streaming subscription this is all taken care of, you simply do something like this: 1) Load the last 50 messages (or whatever number of existing messages suits you) 2) Run your streaming subscription using the most recent of the messages from above as you cursor 3) When you send a message, do nothing and let the subscription handle getting the message you just sent