diff --git a/.changeset/dull-dancers-judge.md b/.changeset/dull-dancers-judge.md new file mode 100644 index 00000000..d4be0b44 --- /dev/null +++ b/.changeset/dull-dancers-judge.md @@ -0,0 +1,5 @@ +--- +'@powersync/common': patch +--- + +Added basic validations for required options in `PowerSyncDatabase` constructor. diff --git a/packages/common/src/client/AbstractPowerSyncDatabase.ts b/packages/common/src/client/AbstractPowerSyncDatabase.ts index 5e7b844e..b8067fe7 100644 --- a/packages/common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/common/src/client/AbstractPowerSyncDatabase.ts @@ -182,7 +182,12 @@ export abstract class AbstractPowerSyncDatabase extends BaseObserver { - return typeof test == 'object' && 'dbFilename' in test; + // typeof null is `object`, but you cannot use the `in` operator on `null. + return test && typeof test == 'object' && 'dbFilename' in test; }; /** diff --git a/packages/web/tests/open.test.ts b/packages/web/tests/open.test.ts index 861cd078..d7ef6a21 100644 --- a/packages/web/tests/open.test.ts +++ b/packages/web/tests/open.test.ts @@ -1,4 +1,4 @@ -import { AbstractPowerSyncDatabase } from '@powersync/common'; +import { AbstractPowerSyncDatabase, Schema } from '@powersync/common'; import { PowerSyncDatabase, WASQLiteDBAdapter, @@ -127,4 +127,93 @@ describe('Open Methods', () => { expect(sharedSpy).toBeCalledTimes(0); expect(dedicatedSpy).toBeCalledTimes(0); }); + + /** + * TypeScript should prevent this kind of error. This scenario could happen + * in pure JavaScript with no language server checking types. + */ + it('Should throw if schema setting is not valid', async () => { + const schemaError = 'The `schema` option should be provided'; + + expect( + () => + new PowerSyncDatabase({ + database: { dbFilename: 'test.sqlite' }, + // @ts-expect-error + schema: null + }) + ).throws(schemaError); + + expect( + () => + new PowerSyncDatabase({ + database: { dbFilename: 'test.sqlite' }, + // @ts-expect-error + schema: {} + }) + ).throws(schemaError); + + expect( + () => + new PowerSyncDatabase({ + database: { dbFilename: 'test.sqlite' }, + // @ts-expect-error + schema: 'schema' + }) + ).throws(schemaError); + + expect( + () => + new PowerSyncDatabase({ + database: { dbFilename: 'test.sqlite' }, + // @ts-expect-error + schema: undefined + }) + ).throws(schemaError); + + // An Extended class should be fine + class ExtendedSchema extends Schema {} + + const extendedClient = new PowerSyncDatabase({ + database: { dbFilename: 'test.sqlite' }, + schema: new ExtendedSchema([]) + }); + + await extendedClient.close(); + }); + + /** + * TypeScript should prevent this kind of error. This scenario could happen + * in pure JavaScript with no language server checking types. + */ + it('Should throw if database setting is not valid', async () => { + const dbError = 'The provided `database` option is invalid.'; + + expect( + () => + new PowerSyncDatabase({ + // @ts-expect-error + database: null, + schema: new Schema([]) + }) + ).throws(dbError); + + expect( + () => + new PowerSyncDatabase({ + // @ts-expect-error + database: {}, + schema: new Schema([]) + }) + ).throws(dbError); + + expect( + () => + new PowerSyncDatabase({ + // @ts-expect-error + database: 'db.sqlite', + schema: new Schema([]) + }) + ).throws(dbError); + }); });