Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: Update Firebase iOS SDK version to v11 #8028

Merged
merged 11 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/scripts/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"indexes": "firestore.indexes.json"
},
"functions": {
"predeploy": ["cd functions && yarn", "cd functions && yarn --prefix \"$RESOURCE_DIR\" build"],
"predeploy": ["cd functions && yarn", "cd functions && yarn --cwd \"$RESOURCE_DIR\" build"],
"source": "functions",
"ignore": [".yarn", "yarn.lock", "*.log", "node_modules"]
},
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/scripts/functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^12.1.1",
"firebase-functions": "^5.0.1"
"firebase-admin": "^12.5.0",
"firebase-functions": "^6.0.1"
},
"devDependencies": {
"firebase-functions-test": "^3.3.0",
"typescript": "^5.4.5"
"typescript": "^5.6.2"
},
"private": true
}
17 changes: 10 additions & 7 deletions .github/workflows/scripts/functions/src/fetchAppCheckToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@
*/

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as functions from 'firebase-functions/v2';
import { CallableRequest } from 'firebase-functions/v2/https';

// Note: this will only work in a live environment, not locally via the Firebase emulator.
export const fetchAppCheckToken = functions.https.onCall(async data => {
const { appId } = data;
const expireTimeMillis = Math.floor(Date.now() / 1000) + 60 * 60;
const result = await admin.appCheck().createToken(appId);
return { ...result, expireTimeMillis };
});
export const fetchAppCheckTokenV2 = functions.https.onCall(
async (req: CallableRequest<{ appId: string }>) => {
const { appId } = req.data;
const expireTimeMillis = Math.floor(Date.now() / 1000) + 60 * 60;
const result = await admin.appCheck().createToken(appId);
return { ...result, expireTimeMillis };
},
);
26 changes: 15 additions & 11 deletions .github/workflows/scripts/functions/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import * as functions from 'firebase-functions';
import * as functions from 'firebase-functions/v2';
import { CallableRequest } from 'firebase-functions/v2/https';

// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
//
export const helloWorld = functions.https.onRequest((request, response) => {
export const helloWorldV2 = functions.https.onRequest((_, response) => {
functions.logger.info('Hello logs!', { structuredData: true });
response.send('{ "data": "Hello from Firebase!" }');
});

export const sleeper = functions.https.onCall(async data => {
functions.logger.info('Sleeper function starting');
return await new Promise(() =>
setTimeout(() => functions.logger.info('done sleeping'), data?.delay ?? 3000),
);
});
export const sleeperV2 = functions.https.onCall(
async (req: CallableRequest<{ delay?: number }>) => {
functions.logger.info('Sleeper function starting');
return await new Promise(() => {
functions.logger.info('Sleeping this long: ' + (req.data.delay ?? 3000));
setTimeout(() => functions.logger.info('done sleeping'), req.data.delay ?? 3000);
});
},
);

export { testFunctionCustomRegion } from './testFunctionCustomRegion';
export { testFunctionDefaultRegion } from './testFunctionDefaultRegion';
export { testFunctionRemoteConfigUpdate } from './testFunctionRemoteConfigUpdate';
export { fetchAppCheckToken } from './fetchAppCheckToken';
export { testFunctionDefaultRegionV2 } from './testFunctionDefaultRegion';
export { testFunctionRemoteConfigUpdateV2 } from './testFunctionRemoteConfigUpdate';
export { fetchAppCheckTokenV2 } from './fetchAppCheckToken';
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
* See License file for more information.
*/

import * as functions from 'firebase-functions';
import * as functions from 'firebase-functions/v1';

// stay v1 here - v2 functions don't support custom regions well,
// they require httpsCallableFromUrl which is tested separately
export const testFunctionCustomRegion = functions
.region('europe-west1')
.https.onCall(() => 'europe-west1');
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,65 @@

import * as assert from 'assert';
import { FirebaseError } from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as functions from 'firebase-functions/v2';
import SAMPLE_DATA from './sample-data';
import { CallableRequest } from 'firebase-functions/v2/https';

export const testFunctionDefaultRegion = functions.https.onCall(data => {
console.log(Date.now(), data);
export const testFunctionDefaultRegionV2 = functions.https.onCall(
(req: CallableRequest<{ type: string; asError: boolean; inputData: any }>) => {
console.log(Date.now(), req.data);

if (typeof data === 'undefined') {
return 'undefined';
}
if (typeof req.data === 'undefined') {
return 'undefined';
}

if (typeof data === 'string') {
return 'string';
}
if (typeof req.data === 'string') {
return 'string';
}

if (typeof data === 'number') {
return 'number';
}
if (typeof req.data === 'number') {
return 'number';
}

if (typeof data === 'boolean') {
return 'boolean';
}
if (typeof req.data === 'boolean') {
return 'boolean';
}

if (data === null) {
return 'null';
}
if (req.data === null) {
return 'null';
}

if (Array.isArray(data)) {
return 'array';
}
if (Array.isArray(req.data)) {
return 'array';
}

const { type, asError, inputData } = data;
if (!Object.hasOwnProperty.call(SAMPLE_DATA, type)) {
throw new functions.https.HttpsError('invalid-argument', 'Invalid test requested.');
}
const { type, asError, inputData } = req.data;
if (!Object.hasOwnProperty.call(SAMPLE_DATA, type)) {
throw new functions.https.HttpsError('invalid-argument', 'Invalid test requested.');
}

const outputData = SAMPLE_DATA[type];
const outputData = SAMPLE_DATA[type];

try {
assert.deepEqual(outputData, inputData);
} catch (e) {
console.error(e);
throw new functions.https.HttpsError(
'invalid-argument',
'Input and Output types did not match.',
(e as FirebaseError).message,
);
}
try {
assert.deepEqual(outputData, inputData);
} catch (e) {
console.error(e);
throw new functions.https.HttpsError(
'invalid-argument',
'Input and Output types did not match.',
(e as FirebaseError).message,
);
}

// all good
if (asError) {
throw new functions.https.HttpsError(
'cancelled',
'Response data was requested to be sent as part of an Error payload, so here we are!',
outputData,
);
}
// all good
if (asError) {
throw new functions.https.HttpsError(
'cancelled',
'Response data was requested to be sent as part of an Error payload, so here we are!',
outputData,
);
}

return outputData;
});
return outputData;
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,77 @@
* See License file for more information.
*/
import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import * as functions from 'firebase-functions/v2';
import { CallableRequest } from 'firebase-functions/v2/https';

admin.initializeApp();
const remoteConfig = admin.remoteConfig();

export const testFunctionRemoteConfigUpdate = functions.https.onCall(data => {
console.log(Date.now(), data);
export const testFunctionRemoteConfigUpdateV2 = functions.https.onCall(
(
req: CallableRequest<{
operations: {
delete: string[] | undefined;
add: { name: string; value: string }[] | undefined;
update: { name: string; value: string }[] | undefined;
};
}>,
) => {
console.log(Date.now(), req);

return new Promise(function (resolve, reject) {
remoteConfig
.getTemplate()
.then((template: any) => {
console.log('received template version: ' + JSON.stringify(template.version));
// console.log('received template: ' + JSON.stringify(template, null, 2));
return new Promise(function (resolve, reject) {
remoteConfig
.getTemplate()
.then((template: any) => {
console.log('received template version: ' + JSON.stringify(template.version));
// console.log('received template: ' + JSON.stringify(template, null, 2));

if (data?.operations['delete'] !== undefined) {
const deletions = data?.operations['delete'];
deletions.forEach((deletion: string) => {
console.log('deleting key: ' + deletion);
if (template.parameters?.deletion !== undefined) {
delete template.parameters.deletion;
}
});
}
if (req.data?.operations['delete'] !== undefined) {
const deletions = req.data?.operations['delete'];
deletions.forEach((deletion: string) => {
console.log('deleting key: ' + deletion);
if (template.parameters?.deletion !== undefined) {
delete template.parameters.deletion;
}
});
}

if (data?.operations['add'] !== undefined) {
const adds = data?.operations['add'];
adds.forEach((add: { name: string; value: any }) => {
console.log('adding key: ' + JSON.stringify(add));
template.parameters[add.name] = {
description: 'realtime test parameter',
defaultValue: {
value: add.value,
},
};
});
}
if (req.data?.operations['add'] !== undefined) {
const adds = req.data?.operations['add'];
adds.forEach((add: { name: string; value: any }) => {
console.log('adding key: ' + JSON.stringify(add));
template.parameters[add.name] = {
description: 'realtime test parameter',
defaultValue: {
value: add.value,
},
};
});
}

if (data?.operations['update'] !== undefined) {
const updates = data?.operations['update'];
updates.forEach((update: { name: string; value: any }) => {
console.log('updating key: ' + JSON.stringify(update));
if (template.parameters[update.name] !== undefined) {
template.parameters[update.name].defaultValue = update.value;
}
});
}
if (req.data?.operations['update'] !== undefined) {
const updates = req.data?.operations['update'];
updates.forEach((update: { name: string; value: any }) => {
console.log('updating key: ' + JSON.stringify(update));
if (template.parameters[update.name] !== undefined) {
template.parameters[update.name].defaultValue = update.value;
}
});
}

// validate the template
remoteConfig.validateTemplate(template).then(template => {
console.log('template is valid after updates.');
remoteConfig.publishTemplate(template).then(template => {
console.log('template published, new version: ' + JSON.stringify(template.version));
resolve({ templateVersion: template.version?.versionNumber });
// validate the template
remoteConfig.validateTemplate(template).then(template => {
console.log('template is valid after updates.');
remoteConfig.publishTemplate(template).then(template => {
console.log('template published, new version: ' + JSON.stringify(template.version));
resolve({ templateVersion: template.version?.versionNumber });
});
});
})
.catch((err: string) => {
console.error('remoteConfig.getTemplate failure: ' + err);
reject({ status: 'failure', message: err });
});
})
.catch((err: string) => {
console.error('remoteConfig.getTemplate failure: ' + err);
reject({ status: 'failure', message: err });
});
});
});
});
},
);
Loading
Loading