Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3d6358a
feat(cloud_functions): httpsCallable.stream support
MichaelVerdon Dec 9, 2025
f20f329
feat: android impl
MichaelVerdon Dec 10, 2025
87b000a
feat: typescript impl
MichaelVerdon Dec 11, 2025
b5aa190
feat: turbomodules impl and use correct native method for android
MichaelVerdon Dec 11, 2025
2024041
feat: tests and event emission working
MichaelVerdon Dec 11, 2025
fe37b79
fix: tests
MichaelVerdon Dec 11, 2025
ff8c3b1
feat: definition tests
MichaelVerdon Dec 12, 2025
9c44d18
feat: iOS impl
MichaelVerdon Dec 12, 2025
bb15bf4
fix: ios stream
MichaelVerdon Dec 12, 2025
3560577
fix: jest
MichaelVerdon Dec 15, 2025
1445156
feat: web impl
MichaelVerdon Dec 15, 2025
d2b94d1
feat: error handling
MichaelVerdon Dec 15, 2025
0cfed52
format: js
MichaelVerdon Dec 15, 2025
bcf8869
fix: ts defs
MichaelVerdon Dec 15, 2025
a4e497d
fix: ts ignore
MichaelVerdon Dec 15, 2025
6c0492f
fix: lint
MichaelVerdon Dec 15, 2025
7ef1474
format: java format
MichaelVerdon Dec 15, 2025
5c2c5f3
format: indentations
MichaelVerdon Dec 15, 2025
65e5a5a
format: indentation
MichaelVerdon Dec 15, 2025
9245d6d
format: clang
MichaelVerdon Dec 15, 2025
14967b1
Merge branch 'main' into cloud-functions-streaming
MichaelVerdon Dec 18, 2025
13e6b2f
fix: readd types from merge conflict fixes
MichaelVerdon Dec 19, 2025
b500b8d
fix(web): web types
MichaelVerdon Dec 19, 2025
b612452
fix: more web types
MichaelVerdon Dec 19, 2025
0544303
fix: stream type
MichaelVerdon Dec 19, 2025
6c81f40
feat: util mock func
MichaelVerdon Dec 19, 2025
856e3b9
fix: mocking
MichaelVerdon Dec 19, 2025
b25f207
chore: format
MichaelVerdon Dec 19, 2025
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
7 changes: 7 additions & 0 deletions .github/workflows/scripts/functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ export { fetchAppCheckTokenV2 } from './fetchAppCheckToken';
export { sendFCM } from './sendFCM';

export { testFetchStream, testFetch } from './vertexaiFunctions';

export {
testStreamingCallable,
testProgressStream,
testComplexDataStream,
testStreamWithError,
} from './testStreamingCallable';
159 changes: 159 additions & 0 deletions .github/workflows/scripts/functions/src/testStreamingCallable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { onCall, CallableRequest, CallableResponse } from 'firebase-functions/v2/https';
import { logger } from 'firebase-functions/v2';

/**
* Test streaming callable function that sends multiple chunks of data
* This function demonstrates Server-Sent Events (SSE) streaming
*/
export const testStreamingCallable = onCall(
async (
req: CallableRequest<{ count?: number; delay?: number }>,
response?: CallableResponse<any>,
) => {
const count = req.data.count || 5;
const delay = req.data.delay || 500;

logger.info('testStreamingCallable called', { count, delay });

// Send chunks of data over time
for (let i = 0; i < count; i++) {
// Wait for the specified delay
await new Promise(resolve => setTimeout(resolve, delay));

if (response) {
await response.sendChunk({
index: i,
message: `Chunk ${i + 1} of ${count}`,
timestamp: new Date().toISOString(),
data: {
value: i * 10,
isEven: i % 2 === 0,
},
});
}
}

// Return final result
return { totalCount: count, message: 'Stream complete' };
},
);

/**
* Test streaming callable that sends progressive updates
*/
export const testProgressStream = onCall(
async (
req: CallableRequest<{ task?: string }>,
response?: CallableResponse<any>,
) => {
const task = req.data.task || 'Processing';

logger.info('testProgressStream called', { task });

const updates = [
{ progress: 0, status: 'Starting...', task },
{ progress: 25, status: 'Loading data...', task },
{ progress: 50, status: 'Processing data...', task },
{ progress: 75, status: 'Finalizing...', task },
{ progress: 100, status: 'Complete!', task },
];

for (const update of updates) {
await new Promise(resolve => setTimeout(resolve, 300));
if (response) {
await response.sendChunk(update);
}
}

return { success: true };
},
);

/**
* Test streaming with complex data types
*/
export const testComplexDataStream = onCall(
async (req: CallableRequest, response?: CallableResponse<any>) => {
logger.info('testComplexDataStream called');

const items = [
{
id: 1,
name: 'Item One',
tags: ['test', 'streaming', 'firebase'],
metadata: {
created: new Date().toISOString(),
version: '1.0.0',
},
},
{
id: 2,
name: 'Item Two',
tags: ['react-native', 'functions'],
metadata: {
created: new Date().toISOString(),
version: '1.0.1',
},
},
{
id: 3,
name: 'Item Three',
tags: ['cloud', 'streaming'],
metadata: {
created: new Date().toISOString(),
version: '2.0.0',
},
},
];

// Stream each item individually
for (const item of items) {
await new Promise(resolve => setTimeout(resolve, 200));
if (response) {
await response.sendChunk(item);
}
}

// Return summary
return {
summary: {
totalItems: items.length,
processedAt: new Date().toISOString(),
},
};
},
);

/**
* Test streaming with error handling
*/
export const testStreamWithError = onCall(
async (
req: CallableRequest<{ shouldError?: boolean; errorAfter?: number }>,
response?: CallableResponse<any>,
) => {
const shouldError = req.data.shouldError !== false;
const errorAfter = req.data.errorAfter || 2;

logger.info('testStreamWithError called', { shouldError, errorAfter });

for (let i = 0; i < 5; i++) {
if (shouldError && i === errorAfter) {
throw new Error('Simulated streaming error after chunk ' + errorAfter);
}

await new Promise(resolve => setTimeout(resolve, 300));
if (response) {
await response.sendChunk({
chunk: i,
message: `Processing chunk ${i + 1}`,
});
}
}

return {
success: true,
message: 'All chunks processed successfully',
};
},
);
10 changes: 10 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ jest.doMock('react-native', () => {
checkForUpdate: jest.fn(),
signOutTester: jest.fn(),
},
RNFBFunctionsModule: {
httpsCallableStream: jest.fn(),
httpsCallableStreamFromUrl: jest.fn(),
removeFunctionsStreaming: jest.fn(),
},
NativeRNFBTurboFunctions: {
httpsCallableStream: jest.fn(),
httpsCallableStreamFromUrl: jest.fn(),
removeFunctionsStreaming: jest.fn(),
},
RNFBCrashlyticsModule: {
isCrashlyticsCollectionEnabled: false,
checkForUnsentReports: jest.fn(),
Expand Down
Loading
Loading