Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
053dc3b
feat: tsconfig for storage
russellwheatley Jan 8, 2026
7ebedb9
package.json
russellwheatley Jan 8, 2026
22367cf
deleted old declaration files
russellwheatley Jan 8, 2026
6c24d19
chore: storage types
russellwheatley Jan 8, 2026
c6ba689
fix: task type
russellwheatley Jan 8, 2026
d4f35a5
chore: modular, namespaced, types and index
russellwheatley Jan 8, 2026
30e1642
convert the rest of the src files to TS
russellwheatley Jan 8, 2026
65b4e23
update web implementation
russellwheatley Jan 8, 2026
db33fe1
type-test
russellwheatley Jan 8, 2026
38185fc
Merge branch 'main' into storage-typescript
russellwheatley Jan 8, 2026
e225e38
remove type declarations from tsconfig root
russellwheatley Jan 8, 2026
aa82bda
remove js files
russellwheatley Jan 8, 2026
6997262
remove another js file
russellwheatley Jan 8, 2026
1eaae1a
fix: dependencies
russellwheatley Jan 8, 2026
ba4cdd6
fix: types and create storage private type
russellwheatley Jan 8, 2026
3abfb9e
chore: remove statics that are added at runtime via app
russellwheatley Jan 9, 2026
3219fbc
fix: update type
russellwheatley Jan 9, 2026
074f261
fix: web types
russellwheatley Jan 9, 2026
e09276a
fix: remove any and ignore
russellwheatley Jan 9, 2026
e2b1a53
fix: storage reference and list types
russellwheatley Jan 9, 2026
a84f1f4
fix: metadata
russellwheatley Jan 9, 2026
4ac3778
refactor: improve types to match existing and update StorageTask
russellwheatley Jan 12, 2026
e9a80d9
Merge branch 'main' into storage-typescript
russellwheatley Feb 2, 2026
0c3bfcd
yarn.lock
russellwheatley Feb 2, 2026
79f0e8e
fix: tsconfig paths
russellwheatley Feb 2, 2026
8f34cb5
fix(web): use types from firebase-js-sdk
russellwheatley Feb 2, 2026
f3711ea
fix: update package.json to match others after publish issues
russellwheatley Feb 2, 2026
2b72c0e
chore: license header
russellwheatley Feb 2, 2026
563524d
fix: internal types and remove any type
russellwheatley Feb 2, 2026
c352849
fix: remove unknown types
russellwheatley Feb 2, 2026
37daabe
fix: types in utils
russellwheatley Feb 2, 2026
0ffafc1
fix: update any to settablemetadata
russellwheatley Feb 2, 2026
0298e44
test: update jest paths
russellwheatley Feb 2, 2026
fd92732
chore: temp fix to ios workflow
russellwheatley Feb 2, 2026
77bc17b
chore: remove modular export
russellwheatley Feb 2, 2026
9c6b102
Merge branch 'main' into storage-typescript
russellwheatley Feb 3, 2026
813ebd8
fix: do not initialise property as null
russellwheatley Feb 3, 2026
ee5637f
fix: storage task observers
russellwheatley Feb 3, 2026
0caa7af
chore: example app for storage
russellwheatley Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
*/

import StorageTask from './StorageTask';
import type { Reference, TaskSnapshot } from './types/storage';

const DOWNLOAD_TASK = 'download';

export default class StorageDownloadTask extends StorageTask {
constructor(storageRef, beginTaskFn) {
constructor(storageRef: Reference, beginTaskFn: (task: StorageTask) => Promise<TaskSnapshot>) {
super(DOWNLOAD_TASK, storageRef, beginTaskFn);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,47 @@
*
*/

import type { Reference } from './types/storage';
import type { ListResultInternal, StorageInternal } from './types/internal';

// To avoid React Native require cycle warnings
let StorageReference = null;
export function provideStorageReferenceClass(storageReference) {
let StorageReference: (new (storage: StorageInternal, path: string) => Reference) | null = null;

export function provideStorageReferenceClass(
storageReference: new (storage: StorageInternal, path: string) => Reference,
): void {
StorageReference = storageReference;
}

export default class StorageListResult {
constructor(storage, nativeData) {
private _nextPageToken: string | null;
private _items: Reference[];
private _prefixes: Reference[];

constructor(storage: StorageInternal, nativeData: ListResultInternal) {
this._nextPageToken = nativeData.nextPageToken || null;
this._items = nativeData.items.map(path => new StorageReference(storage, path));
this._prefixes = nativeData.prefixes.map(path => new StorageReference(storage, path));

if (!StorageReference) {
throw new Error(
'StorageReference class has not been provided. This is likely a module initialization issue.',
);
}

// TypeScript doesn't narrow the type after the null check, so we assign to a const
const StorageReferenceClass = StorageReference;
this._items = nativeData.items.map(path => new StorageReferenceClass(storage, path));
this._prefixes = nativeData.prefixes.map(path => new StorageReferenceClass(storage, path));
}

get items() {
get items(): Reference[] {
return this._items;
}

get nextPageToken() {
get nextPageToken(): string | null {
return this._nextPageToken;
}

get prefixes() {
get prefixes(): Reference[] {
return this._prefixes;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,38 +35,49 @@ import StorageListResult, { provideStorageReferenceClass } from './StorageListRe
import { StringFormat } from './StorageStatics';
import StorageUploadTask from './StorageUploadTask';
import { validateMetadata } from './utils';

export default class StorageReference extends ReferenceBase {
constructor(storage, path) {
import type {
Reference,
SettableMetadata,
ListOptions,
FullMetadata,
Task,
Storage,
} from './types/storage';
import type { ListResultInternal, StorageInternal } from './types/internal';

export default class StorageReference extends ReferenceBase implements Reference {
_storage: StorageInternal;

constructor(storage: StorageInternal, path: string) {
super(path);
this._storage = storage;
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#bucket
*/
get bucket() {
return this._storage._customUrlOrRegion.replace('gs://', '');
get bucket(): string {
return this._storage._customUrlOrRegion!.replace('gs://', '');
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#fullPath
*/
get fullPath() {
get fullPath(): string {
return this.path;
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#name
*/
get name() {
get name(): string {
return pathLastComponent(this.path);
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#parent
*/
get parent() {
get parent(): Reference | null {
const parentPath = pathParent(this.path);
if (parentPath === null) {
return parentPath;
Expand All @@ -77,75 +88,76 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#root
*/
get root() {
get root(): Reference {
return new StorageReference(this._storage, '/');
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#storage
*/
get storage() {
get storage(): Storage {
return this._storage;
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#child
*/
child(path) {
child(path: string): Reference {
const childPath = pathChild(this.path, path);
return new StorageReference(this._storage, childPath);
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete
*/
delete() {
delete(): Promise<void> {
return this._storage.native.delete(this.toString());
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL
*/
getDownloadURL() {
getDownloadURL(): Promise<string> {
return this._storage.native.getDownloadURL(this.toString());
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata
*/
getMetadata() {
getMetadata(): Promise<FullMetadata> {
return this._storage.native.getMetadata(this.toString());
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#list
*/
list(options) {
list(options?: ListOptions): Promise<StorageListResult> {
if (!isUndefined(options) && !isObject(options)) {
throw new Error(
"firebase.storage.StorageReference.list(*) 'options' expected an object value.",
);
}

const listOptions = {
const listOptions: { maxResults: number; pageToken?: string } = {
maxResults: 1000,
};

if (options) {
if (hasOwnProperty(options, 'maxResults')) {
if (!isNumber(options.maxResults) || !isInteger(options.maxResults)) {
const maxResults = options.maxResults;
if (!isNumber(maxResults) || !isInteger(maxResults)) {
throw new Error(
"firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value.",
);
}

if (options.maxResults < 1 || options.maxResults > 1000) {
if (maxResults < 1 || maxResults > 1000) {
throw new Error(
"firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value between 1-1000.",
);
}

listOptions.maxResults = options.maxResults;
listOptions.maxResults = maxResults;
}

if (options.pageToken) {
Expand All @@ -161,29 +173,34 @@ export default class StorageReference extends ReferenceBase {

return this._storage.native
.list(this.toString(), listOptions)
.then(data => new StorageListResult(this._storage, data));
.then((data: ListResultInternal) => new StorageListResult(this._storage, data));
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#listAll
*/
listAll() {
listAll(): Promise<StorageListResult> {
return this._storage.native
.listAll(this.toString())
.then(data => new StorageListResult(this._storage, data));
.then((data: ListResultInternal) => new StorageListResult(this._storage, data));
}

/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#put
*/
put(data, metadata) {
put(data: Blob | Uint8Array | ArrayBuffer, metadata?: SettableMetadata): Task {
if (!isUndefined(metadata)) {
validateMetadata(metadata, false);
}

return new StorageUploadTask(this, task =>
Base64.fromData(data).then(({ string, format }) => {
const { _string, _format, _metadata } = this._updateString(string, format, metadata, false);
const { _string, _format, _metadata } = this._updateString(
string as string,
format,
metadata,
false,
);
return this._storage.native.putString(
this.toString(),
_string,
Expand All @@ -198,7 +215,11 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putString
*/
putString(string, format = StringFormat.RAW, metadata) {
putString(
string: string,
format: (typeof StringFormat)[keyof typeof StringFormat] = StringFormat.RAW,
metadata?: SettableMetadata,
): Task {
const { _string, _format, _metadata } = this._updateString(string, format, metadata, false);

return new StorageUploadTask(this, task =>
Expand All @@ -209,7 +230,7 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#fullPath
*/
toString() {
toString(): string {
if (this.path.length <= 1) {
return `${this._storage._customUrlOrRegion}`;
}
Expand All @@ -220,7 +241,7 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
*/
updateMetadata(metadata) {
updateMetadata(metadata: SettableMetadata): Promise<FullMetadata> {
validateMetadata(metadata);
return this._storage.native.updateMetadata(this.toString(), metadata);
}
Expand All @@ -232,7 +253,7 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference
*/
writeToFile(filePath) {
writeToFile(filePath: string): Task {
if (!isString(filePath)) {
throw new Error(
"firebase.storage.StorageReference.writeToFile(*) 'filePath' expects a string value.",
Expand All @@ -247,7 +268,7 @@ export default class StorageReference extends ReferenceBase {
/**
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference
*/
putFile(filePath, metadata) {
putFile(filePath: string, metadata?: SettableMetadata): Task {
if (!isUndefined(metadata)) {
validateMetadata(metadata, false);
}
Expand All @@ -263,7 +284,12 @@ export default class StorageReference extends ReferenceBase {
);
}

_updateString(string, format, metadata, update = false) {
_updateString(
string: string,
format: (typeof StringFormat)[keyof typeof StringFormat],
metadata: SettableMetadata | undefined,
update = false,
): { _string: string; _format: string; _metadata: SettableMetadata | undefined } {
if (!isString(string)) {
throw new Error(
"firebase.storage.StorageReference.putString(*, _, _) 'string' expects a string value.",
Expand Down Expand Up @@ -301,7 +327,7 @@ export default class StorageReference extends ReferenceBase {
if (isUndefined(metadata)) {
_metadata = {};
}
_metadata.contentType = mediaType;
_metadata!.contentType = mediaType;
_string = base64String;
_format = StringFormat.BASE64;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ export const StringFormat = {
BASE64: 'base64',
BASE64URL: 'base64url',
DATA_URL: 'data_url',
};
} as const;

export const TaskEvent = {
STATE_CHANGED: 'state_changed',
};
} as const;

export const TaskState = {
RUNNING: 'running',
PAUSED: 'paused',
SUCCESS: 'success',
CANCELLED: 'cancelled',
ERROR: 'error',
};
} as const;
Loading
Loading