├── .gitignore
├── kamick-supabaseprovider-1.0.0.tgz
├── .github
└── workflows
│ └── publish.yml
├── LICENSE.txt
├── package.json
├── README.md
├── src
└── index.ts
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
3 | # Ignore test-related files
4 | /coverage.data
5 | /coverage/
6 |
7 | # Build files
8 | /dist
--------------------------------------------------------------------------------
/kamick-supabaseprovider-1.0.0.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinamick/supabaseprovider/HEAD/kamick-supabaseprovider-1.0.0.tgz
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Package to npmjs
2 | on:
3 | push:
4 | tags:
5 | - '*'
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | # Setup .npmrc file to publish to npm
12 | - uses: actions/setup-node@v3
13 | with:
14 | node-version: '20.x'
15 | registry-url: 'https://registry.npmjs.org'
16 | - run: npm ci
17 | - run: npm publish --access=public
18 | env:
19 | NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_KEY }}
20 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Kevin Amick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@kamick/supabaseprovider",
3 | "version": "1.0.0",
4 | "description": "A TipTap collboration provider using Supabase realtime",
5 | "main": "index.js",
6 | "module": "./dist/index.mjs",
7 | "types": "./dist/index.d.ts",
8 | "files": [
9 | "dist"
10 | ],
11 | "scripts": {
12 | "build": "tsup",
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/kevinamick/supabaseprovider.git"
18 | },
19 | "keywords": [
20 | "tiptap",
21 | "supabase",
22 | "collaboration"
23 | ],
24 | "author": "Kevin Amick",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/kevinamick/supabaseprovider/issues"
28 | },
29 | "homepage": "https://github.com/kevinamick/supabaseprovider#readme",
30 | "devDependencies": {
31 | "ts-node": "^10.9.2",
32 | "tsup": "^8.0.2",
33 | "typescript": "^5.3.3"
34 | },
35 | "dependencies": {
36 | "@supabase/supabase-js": "^2.39.6",
37 | "debounce": "^2.0.0",
38 | "events": "^3.3.0",
39 | "js-base64": "^3.7.6"
40 | },
41 | "peerDependencies": {
42 | "y-protocols": "^1.0.6",
43 | "yjs": "^13.6.10"
44 | },
45 | "tsup": {
46 | "entry": [
47 | "src/index.ts"
48 | ],
49 | "format": [
50 | "cjs",
51 | "esm"
52 | ],
53 | "dts": true,
54 | "splitting": false,
55 | "sourcemap": true,
56 | "clean": true
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
21 | [![Forks][forks-shield]][forks-url]
22 | [![Stargazers][stars-shield]][stars-url]
23 | [![Issues][issues-shield]][issues-url]
24 | [![MIT License][license-shield]][license-url]
25 |
26 |
27 |
28 |
29 |
30 | Table of Contents
31 |
32 | -
33 | About The Project
34 |
35 | - Usage
36 | - Roadmap
37 | - Contributing
38 | - License
39 | - Contact
40 |
41 |
42 |
43 |
44 |
45 |
46 | ## About The Project
47 |
48 | Easily set up collaborative editing with Supabase Realtime! Built with [YJS](https://docs.yjs.dev/).
49 |
50 | Not recommended for production use in its current state.
51 |
52 | Contributors welcome!
53 |
54 |
(back to top)
55 |
56 |
57 | ## Usage
58 |
59 | ```json
60 | "@kamick/supabaseprovider": "^0.0.2",
61 | ```
62 |
63 | Input:
64 | ```typescript
65 | export interface SupabaseProviderConfiguration {
66 | /**
67 | * The identifier/name of your document
68 | */
69 | name: string;
70 | /**
71 | * The actual Y.js document
72 | */
73 | document: Y.Doc;
74 | /**
75 | * The awareness instance
76 | */
77 | awareness?: Awareness;
78 | /**
79 | * Details about the database to connect to
80 | */
81 | databaseDetails: {
82 | schema: string,
83 | table: string,
84 | updateColumns: { name: string, content: string },
85 | conflictColumns: string
86 | }
87 | }
88 | ```
89 |
90 | Example usage with React:
91 | ```javascript
92 | const supabase = createClientComponentClient();
93 | const router = useRouter();
94 | const doc = useMemo(() => new Y.Doc(), []);
95 | const provider =
96 | useMemo(() => new SupabaseProvider(supabase, {
97 | name: documentName,
98 | document: doc,
99 | databaseDetails: {
100 | schema: {schema},
101 | table: {table},
102 | updateColumns: { name: {column_name}, content: {column_content} },
103 | conflictColumns: {conflict_columns_comma_concat},
104 | },
105 | }), [doc, documentName, supabase]);
106 |
107 | return ;
108 |
109 | ```
110 |
111 | (back to top)
112 |
113 |
114 |
115 |
116 | ## Roadmap
117 |
118 | - [ ] Add Changelog
119 | - [ ] Add Additional Templates w/ Examples
120 | - [ ] Add Testing
121 | - [ ] Production ready
122 |
123 | See the [open issues](https://github.com/kevinamick/supabaseprovider/issues) for a full list of proposed features (and known issues).
124 |
125 | (back to top)
126 |
127 |
128 |
129 |
130 | ## Contributing
131 |
132 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
133 |
134 | If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
135 | Don't forget to give the project a star! Thanks again!
136 |
137 | 1. Fork the Project
138 | 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
139 | 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
140 | 4. Push to the Branch (`git push origin feature/AmazingFeature`)
141 | 5. Open a Pull Request
142 |
143 | (back to top)
144 |
145 |
146 |
147 |
148 | ## License
149 |
150 | Distributed under the MIT License. See `LICENSE.txt` for more information.
151 |
152 | (back to top)
153 |
154 |
155 |
156 |
157 | ## Contact
158 |
159 | Kevin Amick - [@kevinamick](https://twitter.com/kevinamick) - kevinamick81@gmail.com
160 |
161 | Project Link: [https://github.com/kevinamick/supabaseprovider](https://github.com/your_username/repo_name)
162 |
163 | (back to top)
164 |
165 |
166 |
167 | [forks-shield]: https://img.shields.io/github/forks/kevinamick/supabaseprovider
168 | [forks-url]: https://github.com/kevinamick/supabaseprovider/network/members
169 | [stars-shield]: https://img.shields.io/github/stars/kevinamick/supabaseprovider
170 | [stars-url]: https://github.com/kevinamick/supabaseprovider/stargazers
171 | [issues-shield]: https://img.shields.io/github/issues/kevinamick/supabaseprovider
172 | [issues-url]: https://github.com/kevinamick/supabaseprovider/issues
173 | [license-shield]: https://img.shields.io/github/license/kevinamick/supabaseprovider
174 | [license-url]: https://github.com/kevinamick/supabaseprovider/blob/main/LICENSE.txt
175 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
176 | [linkedin-url]: https://linkedin.com/in/kevinamick
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { RealtimeChannel, SupabaseClient } from "@supabase/supabase-js";
2 | import debounce from 'debounce';
3 | import { EventEmitter } from 'events';
4 | import { fromUint8Array, toUint8Array } from "js-base64";
5 | import { Awareness, removeAwarenessStates, encodeAwarenessUpdate, applyAwarenessUpdate } from 'y-protocols/awareness'
6 | import * as Y from "yjs";
7 |
8 | export interface SupabaseProviderConfiguration {
9 | /**
10 | * The identifier/name of your document
11 | */
12 | name: string;
13 | /**
14 | * The actual Y.js document
15 | */
16 | document: Y.Doc;
17 | /**
18 | * The awareness instance
19 | */
20 | awareness?: Awareness;
21 | /**
22 | * Details about the database to connect to
23 | */
24 | databaseDetails: {
25 | schema: string,
26 | table: string,
27 | updateColumns: { name: string, content: string },
28 | conflictColumns: string
29 | }
30 | }
31 |
32 | export class SupabaseProvider extends EventEmitter {
33 | public configuration: SupabaseProviderConfiguration = {
34 | name: '',
35 | // @ts-ignore
36 | document: undefined,
37 | // @ts-ignore
38 | awareness: undefined,
39 | databaseDetails: {
40 | schema: '',
41 | table: '',
42 | updateColumns: { name: '', content: '' },
43 | conflictColumns: ''
44 | }
45 | }
46 |
47 | private supabase: SupabaseClient;
48 | private channel: RealtimeChannel | null = null;
49 | private awareness: Awareness | null = null;
50 | private version: number = 0;
51 | public callbacks: { [key: string]: Function[] } = {}
52 |
53 | constructor(supabase: SupabaseClient, config: SupabaseProviderConfiguration) {
54 | super();
55 | this.setConfiguration(config);
56 | this.configuration.document = config.document ? config.document : new Y.Doc();
57 | this.awareness = config.awareness ? config.awareness : new Awareness(this.configuration.document);
58 | this.supabase = supabase;
59 |
60 | this.on('connect', this.onConnect);
61 | this.on('disconnect', this.onDisconnect);
62 | this.document.on('update', debounce(this.documentUpdateHandler.bind(this), 1000));
63 | this.awareness?.on('update', debounce(this.onAwarenessUpdate.bind(this), 1000))
64 | this.connect();
65 |
66 | if (typeof window !== 'undefined') {
67 | window.addEventListener('beforeunload', this.removeSelfFromAwarenessOnUnload);
68 | } else if (typeof process !== 'undefined') {
69 | process.on('exit', () => this.removeSelfFromAwarenessOnUnload);
70 | }
71 | }
72 |
73 | public setConfiguration(configuration: Partial = {}): void {
74 | this.configuration = { ...this.configuration, ...configuration }
75 | }
76 |
77 | get document() {
78 | return this.configuration.document;
79 | }
80 |
81 | private async documentUpdateHandler(update: Uint8Array, origin?: any) {
82 | if (origin === this) {
83 | return;
84 | }
85 |
86 | const dbDocument = fromUint8Array(Y.encodeStateAsUpdate(this.document));
87 |
88 | const res = await this.supabase
89 | .from(this.configuration.databaseDetails.table)
90 | .upsert({
91 | [this.configuration.databaseDetails.updateColumns.name]: this.configuration.name,
92 | [this.configuration.databaseDetails.updateColumns.content]: dbDocument,
93 | }, this.configuration.databaseDetails.conflictColumns ? { onConflict: this.configuration.databaseDetails.conflictColumns } : {});
94 |
95 | if (res.status === 201 || res.status === 200) {
96 | this.emit('save', this.version);
97 | return this.channel!.send({
98 | type: 'broadcast',
99 | event: 'update',
100 | payload: {dbDocument},
101 | });
102 | } else {
103 | return Error(`Document not stored due to error: ${res.error}`);
104 | }
105 | }
106 |
107 | private onAwarenessUpdate({ added, updated, removed }: any, origin: any) {
108 | const changedClients = added.concat(updated).concat(removed);
109 | const awarenessUpdate = encodeAwarenessUpdate(this.awareness!, changedClients);
110 |
111 | if (this.channel) {
112 | this.channel.send({
113 | type: 'broadcast',
114 | event: 'awareness',
115 | payload: {awareness: fromUint8Array(awarenessUpdate)},
116 | });
117 | }
118 | }
119 |
120 | removeSelfFromAwarenessOnUnload() {
121 | removeAwarenessStates(this.awareness!, [this.document.clientID], 'window unload');
122 | }
123 |
124 | private async onConnect() {
125 | const { data, error } = await this.supabase
126 | .from(this.configuration.databaseDetails.table)
127 | .select(`${this.configuration.databaseDetails.updateColumns.content}`)
128 | .eq(this.configuration.databaseDetails.updateColumns.name, this.configuration.name)
129 | .single();
130 |
131 | if (error) {
132 | console.error(error);
133 | return;
134 | }
135 |
136 | if (data && data[this.configuration.databaseDetails.updateColumns.content]) {
137 | try {
138 | const dbDocument = toUint8Array(data[this.configuration.databaseDetails.updateColumns.content]);
139 | this.version++;
140 | Y.applyUpdate(this.document, dbDocument);
141 | } catch (error) {
142 | console.error(error);
143 | }
144 | }
145 |
146 | this.emit('status', [{ status: 'connected' }]);
147 |
148 | if (this.awareness && this.awareness.getLocalState() !== null) {
149 | const awarenessUpdate = encodeAwarenessUpdate(this.awareness, [this.document.clientID]);
150 | this.emit('awareness', awarenessUpdate);
151 | }
152 | }
153 |
154 | private connect() {
155 | this.channel = this.supabase.channel(this.configuration.name);
156 | this.startSync();
157 | }
158 |
159 | private startSync() {
160 | this.channel!.on('broadcast',
161 | { event: 'update' },
162 | (event) => {
163 | this.onReceiveUpdate(event);
164 | })
165 | .on('broadcast',
166 | { event: 'awareness' },
167 | ({ payload }) => {
168 | const update = toUint8Array(payload.awareness);
169 | applyAwarenessUpdate(this.awareness!, update, this);
170 | })
171 | .subscribe((status, err) => {
172 | switch (status) {
173 | case 'SUBSCRIBED':
174 | this.emit('connect', this);
175 | break;
176 | case 'CHANNEL_ERROR':
177 | // this.emit('error', this);
178 | break;
179 | case 'TIMED_OUT':
180 | this.emit('disconnect', this);
181 | break;
182 | case 'CLOSED':
183 | this.emit('disconnect', this);
184 | break;
185 | default:
186 | break;
187 | }
188 | });
189 | }
190 |
191 | private onReceiveUpdate({ event, payload }: { event: string, [key: string]: any }) {
192 | const update = toUint8Array(payload.dbDocument);
193 | try {
194 | this.version++;
195 | Y.applyUpdate(this.document, update, this);
196 | } catch (error) {
197 | console.error(error);
198 | }
199 | }
200 |
201 | private disconnect() {
202 | if (this.channel) {
203 | this.supabase.removeChannel(this.channel);
204 | this.channel = null;
205 | }
206 | }
207 |
208 | public onDisconnect() {
209 | this.emit('status', [{ status: 'disconnected' }]);
210 |
211 | if (this.awareness) {
212 | const states = Array.from(this.awareness.getStates().keys()).filter((client) => client !== this.document.clientID);
213 | removeAwarenessStates(this.awareness, states, this);
214 | }
215 | }
216 |
217 | public destroy() {
218 | this.removeAllListeners();
219 | this.disconnect();
220 | this.document.off('update', this.documentUpdateHandler);
221 | this.awareness?.off('update', this.onAwarenessUpdate);
222 |
223 | if (typeof window !== 'undefined') {
224 | window.removeEventListener('beforeunload', this.removeSelfFromAwarenessOnUnload);
225 | } else if (typeof process !== 'undefined') {
226 | process.off('exit', () => this.removeSelfFromAwarenessOnUnload);
227 | }
228 |
229 | if (this.channel) {
230 | this.disconnect();
231 | }
232 | }
233 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig to read more about this file */
4 |
5 | /* Projects */
6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
12 |
13 | /* Language and Environment */
14 | "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
16 | // "jsx": "preserve", /* Specify what JSX code is generated. */
17 | // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
26 |
27 | /* Modules */
28 | "module": "commonjs", /* Specify what module code is generated. */
29 | // "rootDir": "./", /* Specify the root folder within your source files. */
30 | // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
31 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
35 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
38 | // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
39 | // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
40 | // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
41 | // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
42 | // "resolveJsonModule": true, /* Enable importing .json files. */
43 | // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
44 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
45 |
46 | /* JavaScript Support */
47 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
48 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
49 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
50 |
51 | /* Emit */
52 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
53 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
54 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
55 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
56 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
57 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
58 | "outDir": "dist", /* Specify an output folder for all emitted files. */
59 | // "removeComments": true, /* Disable emitting comments. */
60 | // "noEmit": true, /* Disable emitting files from a compilation. */
61 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
62 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
63 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
64 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
65 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
66 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
67 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
68 | // "newLine": "crlf", /* Set the newline character for emitting files. */
69 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
70 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
71 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
72 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
73 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
74 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
75 |
76 | /* Interop Constraints */
77 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
78 | // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
79 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
80 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
81 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
82 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
83 |
84 | /* Type Checking */
85 | "strict": true, /* Enable all strict type-checking options. */
86 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
87 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
88 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
89 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
90 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
91 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
92 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
93 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
94 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
95 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
96 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
97 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
98 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
99 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
100 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
101 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
102 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
103 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
104 |
105 | /* Completeness */
106 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
107 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
108 | }
109 | }
110 |
--------------------------------------------------------------------------------