@firebase/data-connect
Advanced tools
Comparing version 0.0.2-dataconnect-preview.877f8b7d0 to 0.0.3-canary.beaa4dffb
@@ -11,3 +11,3 @@ 'use strict'; | ||
const name = "@firebase/data-connect"; | ||
const version = "0.0.2-dataconnect-preview.877f8b7d0"; | ||
const version = "0.0.3-canary.beaa4dffb"; | ||
@@ -56,2 +56,56 @@ /** | ||
*/ | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
class AppCheckTokenProvider { | ||
constructor(appName_, appCheckProvider) { | ||
this.appName_ = appName_; | ||
this.appCheckProvider = appCheckProvider; | ||
this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); | ||
if (!this.appCheck) { | ||
void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(appCheck => (this.appCheck = appCheck)).catch()); | ||
} | ||
} | ||
getToken(forceRefresh) { | ||
if (!this.appCheck) { | ||
return new Promise((resolve, reject) => { | ||
// Support delayed initialization of FirebaseAppCheck. This allows our | ||
// customers to initialize the RTDB SDK before initializing Firebase | ||
// AppCheck and ensures that all requests are authenticated if a token | ||
// becomes available before the timoeout below expires. | ||
setTimeout(() => { | ||
if (this.appCheck) { | ||
this.getToken(forceRefresh).then(resolve, reject); | ||
} | ||
else { | ||
resolve(null); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
return this.appCheck.getToken(forceRefresh); | ||
} | ||
addTokenChangeListener(listener) { | ||
var _a; | ||
void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(appCheck => appCheck.addTokenListener(listener))); | ||
} | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
const Code = { | ||
@@ -63,3 +117,4 @@ OTHER: 'other', | ||
INVALID_ARGUMENT: 'invalid-argument', | ||
PARTIAL_ERROR: 'partial-error' | ||
PARTIAL_ERROR: 'partial-error', | ||
UNAUTHORIZED: 'unauthorized' | ||
}; | ||
@@ -131,2 +186,3 @@ /** An error returned by a DataConnect operation. */ | ||
*/ | ||
// @internal | ||
class FirebaseAuthProvider { | ||
@@ -174,3 +230,4 @@ constructor(_appName, _options, _authProvider) { | ||
.get() | ||
.then(auth => auth.removeAuthTokenListener(listener)); | ||
.then(auth => auth.removeAuthTokenListener(listener)) | ||
.catch(err => logError(err)); | ||
} | ||
@@ -415,3 +472,3 @@ } | ||
} | ||
return `${baseUrl}/v1alpha/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
return `${baseUrl}/v1beta/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
} | ||
@@ -444,3 +501,10 @@ function addToken(url, apiKey) { | ||
let connectFetch = globalThis.fetch; | ||
function dcFetch(url, body, { signal }, accessToken) { | ||
function getGoogApiClientValue(_isUsingGen) { | ||
let str = 'gl-js/ fire/' + SDK_VERSION; | ||
if (_isUsingGen) { | ||
str += ' web/gen'; | ||
} | ||
return str; | ||
} | ||
function dcFetch(url, body, { signal }, appId, accessToken, appCheckToken, _isUsingGen) { | ||
if (!connectFetch) { | ||
@@ -450,3 +514,4 @@ throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!'); | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
'Content-Type': 'application/json', | ||
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) | ||
}; | ||
@@ -456,2 +521,8 @@ if (accessToken) { | ||
} | ||
if (appId) { | ||
headers['x-firebase-gmpid'] = appId; | ||
} | ||
if (appCheckToken) { | ||
headers['X-Firebase-AppCheck'] = appCheckToken; | ||
} | ||
const bodyStr = JSON.stringify(body); | ||
@@ -464,5 +535,6 @@ logDebug(`Making request out to ${url} with body: ${bodyStr}`); | ||
signal | ||
}).catch(err => { | ||
throw new DataConnectError(Code.OTHER, "Failed to fetch: " + JSON.stringify(err)); | ||
}) | ||
.catch(err => { | ||
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); | ||
}) | ||
.then(async (response) => { | ||
@@ -476,5 +548,9 @@ let jsonResponse = null; | ||
} | ||
const message = getMessage(jsonResponse); | ||
if (response.status >= 400) { | ||
logError('Error while performing request: ' + JSON.stringify(jsonResponse)); | ||
throw new DataConnectError(Code.OTHER, JSON.stringify(jsonResponse)); | ||
if (response.status === 401) { | ||
throw new DataConnectError(Code.UNAUTHORIZED, message); | ||
} | ||
throw new DataConnectError(Code.OTHER, message); | ||
} | ||
@@ -492,2 +568,8 @@ return jsonResponse; | ||
} | ||
function getMessage(obj) { | ||
if ('message' in obj) { | ||
return obj.message; | ||
} | ||
return JSON.stringify(obj); | ||
} | ||
@@ -511,6 +593,9 @@ /** | ||
class RESTTransport { | ||
constructor(options, apiKey, authProvider, transportOptions) { | ||
var _a; | ||
constructor(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen = false) { | ||
var _a, _b; | ||
this.apiKey = apiKey; | ||
this.appId = appId; | ||
this.authProvider = authProvider; | ||
this.appCheckProvider = appCheckProvider; | ||
this._isUsingGen = _isUsingGen; | ||
this._host = ''; | ||
@@ -522,3 +607,4 @@ this._location = 'l'; | ||
this._accessToken = null; | ||
this._authInitialized = false; | ||
this._appCheckToken = null; | ||
this._lastToken = null; | ||
// TODO(mtewani): Update U to include shape of body defined in line 13. | ||
@@ -528,12 +614,11 @@ this.invokeQuery = (queryName, body) => { | ||
// TODO(mtewani): Update to proper value | ||
const withAuth = this.getWithAuth().then(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this._accessToken); | ||
}); | ||
const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen)); | ||
return { | ||
then: withAuth.then.bind(withAuth) | ||
then: withAuth.then.bind(withAuth), | ||
catch: withAuth.catch.bind(withAuth) | ||
}; | ||
@@ -543,3 +628,3 @@ }; | ||
const abortController = new AbortController(); | ||
const taskResult = this.getWithAuth().then(() => { | ||
const taskResult = this.withRetry(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), { | ||
@@ -549,3 +634,3 @@ name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
variables: body | ||
}, abortController, this._accessToken); | ||
}, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen); | ||
}); | ||
@@ -584,2 +669,7 @@ return { | ||
}); | ||
(_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(result => { | ||
const { token } = result; | ||
logDebug(`New App Check Token Available: ${token}`); | ||
this._appCheckToken = token; | ||
}); | ||
} | ||
@@ -606,22 +696,48 @@ get endpointUrl() { | ||
} | ||
getWithAuth() { | ||
async getWithAuth(forceToken = false) { | ||
var _a; | ||
let starterPromise = new Promise(resolve => resolve(this._accessToken)); | ||
if (!this._authInitialized) { | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ false) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
if (this.appCheckProvider) { | ||
this._appCheckToken = (_a = (await this.appCheckProvider.getToken())) === null || _a === void 0 ? void 0 : _a.token; | ||
} | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ forceToken) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
return starterPromise; | ||
} | ||
_setLastToken(lastToken) { | ||
this._lastToken = lastToken; | ||
} | ||
withRetry(promiseFactory, retry = false) { | ||
let isNewToken = false; | ||
return this.getWithAuth(retry) | ||
.then(res => { | ||
isNewToken = this._lastToken !== res; | ||
this._lastToken = res; | ||
return res; | ||
}) | ||
.then(promiseFactory) | ||
.catch(err => { | ||
// Only retry if the result is unauthorized and the last token isn't the same as the new one. | ||
if ('code' in err && | ||
err.code === Code.UNAUTHORIZED && | ||
!retry && | ||
isNewToken) { | ||
logDebug('Retrying due to unauthorized'); | ||
return this.withRetry(promiseFactory, true); | ||
} | ||
throw err; | ||
}); | ||
} | ||
} | ||
@@ -645,7 +761,14 @@ | ||
*/ | ||
function mutationRef(dcInstance, queryName, variables) { | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
* @returns `MutationRef` | ||
*/ | ||
function mutationRef(dcInstance, mutationName, variables) { | ||
dcInstance.setInitialized(); | ||
const ref = { | ||
dataConnect: dcInstance, | ||
name: queryName, | ||
name: mutationName, | ||
refType: MUTATION_STR, | ||
@@ -656,2 +779,5 @@ variables: variables | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
class MutationManager { | ||
@@ -674,2 +800,7 @@ constructor(_transport) { | ||
} | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
function executeMutation(mutationRef) { | ||
@@ -709,11 +840,17 @@ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
class DataConnect { | ||
// @internal | ||
constructor(app, | ||
// TODO(mtewani): Replace with _dataConnectOptions in the future | ||
dataConnectOptions, _authProvider) { | ||
dataConnectOptions, _authProvider, _appCheckProvider) { | ||
this.app = app; | ||
this.dataConnectOptions = dataConnectOptions; | ||
this._authProvider = _authProvider; | ||
this._appCheckProvider = _appCheckProvider; | ||
this.isEmulator = false; | ||
this.initialized = false; | ||
this._initialized = false; | ||
this._isUsingGeneratedSdk = false; | ||
if (typeof process !== 'undefined' && process.env) { | ||
@@ -728,2 +865,8 @@ const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; | ||
} | ||
// @internal | ||
_useGeneratedSdk() { | ||
if (!this._isUsingGeneratedSdk) { | ||
this._isUsingGeneratedSdk = true; | ||
} | ||
} | ||
_delete() { | ||
@@ -733,2 +876,3 @@ app._removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); | ||
} | ||
// @internal | ||
getSettings() { | ||
@@ -739,4 +883,5 @@ const copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); | ||
} | ||
// @internal | ||
setInitialized() { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
return; | ||
@@ -751,4 +896,7 @@ } | ||
} | ||
this.initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider); | ||
if (this._appCheckProvider) { | ||
this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); | ||
} | ||
this._initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); | ||
if (this._transportOptions) { | ||
@@ -760,4 +908,5 @@ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); | ||
} | ||
// @internal | ||
enableEmulator(transportOptions) { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
logError('enableEmulator called after initialization'); | ||
@@ -770,2 +919,9 @@ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
function connectDataConnectEmulator(dc, host, port, sslEnabled = false) { | ||
@@ -785,3 +941,3 @@ dc.enableEmulator({ host, port, sslEnabled }); | ||
} | ||
if (!app$1) { | ||
if (!app$1 || Object.keys(app$1).length === 0) { | ||
app$1 = app.getApp(); | ||
@@ -800,5 +956,3 @@ } | ||
} | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
validateDCOptions(dcOptions); | ||
logDebug('Creating new DataConnect instance'); | ||
@@ -811,2 +965,25 @@ // Initialize with options. | ||
} | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
function validateDCOptions(dcOptions) { | ||
const fields = ['connector', 'location', 'service']; | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
fields.forEach(field => { | ||
if (dcOptions[field] === null || dcOptions[field] === undefined) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`); | ||
} | ||
}); | ||
return true; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
function terminate(dataConnect) { | ||
@@ -838,2 +1015,3 @@ return dataConnect._delete(); | ||
const authProvider = container.getProvider('auth-internal'); | ||
const appCheckProvider = container.getProvider('app-check-internal'); | ||
let newOpts = options; | ||
@@ -843,3 +1021,6 @@ if (settings) { | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider); | ||
if (!app.options.projectId) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); | ||
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); | ||
@@ -867,5 +1048,18 @@ app.registerVersion(name, version, variant); | ||
*/ | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
function executeQuery(queryRef) { | ||
return queryRef.dataConnect._queryManager.executeQuery(queryRef); | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @param initialCache initial cache to use for client hydration | ||
* @returns `QueryRef` | ||
*/ | ||
function queryRef(dcInstance, queryName, variables, initialCache) { | ||
@@ -881,2 +1075,7 @@ dcInstance.setInitialized(); | ||
} | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
function toQueryRef(serializedRef) { | ||
@@ -903,2 +1102,53 @@ const { refInfo: { name, variables, connectorConfig } } = serializedRef; | ||
*/ | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { | ||
let dcInstance; | ||
let realVars; | ||
if (dcOrVars && 'enableEmulator' in dcOrVars) { | ||
dcInstance = dcOrVars; | ||
realVars = vars; | ||
} | ||
else { | ||
dcInstance = getDataConnect(connectorConfig); | ||
realVars = dcOrVars; | ||
} | ||
if (!dcInstance || (!realVars && validateVars)) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); | ||
} | ||
return { dc: dcInstance, vars: realVars }; | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observerOrOnNext observer object or next function. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { | ||
@@ -943,4 +1193,2 @@ let ref; | ||
exports.DataConnect = DataConnect; | ||
exports.FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR; | ||
exports.FirebaseAuthProvider = FirebaseAuthProvider; | ||
exports.MUTATION_STR = MUTATION_STR; | ||
@@ -962,2 +1210,4 @@ exports.MutationManager = MutationManager; | ||
exports.toQueryRef = toQueryRef; | ||
exports.validateArgs = validateArgs; | ||
exports.validateDCOptions = validateDCOptions; | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -7,3 +7,3 @@ import { _removeServiceInstance, getApp, _getProvider, _registerComponent, registerVersion, SDK_VERSION as SDK_VERSION$1 } from '@firebase/app'; | ||
const name = "@firebase/data-connect"; | ||
const version = "0.0.2-dataconnect-preview.877f8b7d0"; | ||
const version = "0.0.3-canary.beaa4dffb"; | ||
@@ -52,2 +52,56 @@ /** | ||
*/ | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
class AppCheckTokenProvider { | ||
constructor(appName_, appCheckProvider) { | ||
this.appName_ = appName_; | ||
this.appCheckProvider = appCheckProvider; | ||
this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); | ||
if (!this.appCheck) { | ||
void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(appCheck => (this.appCheck = appCheck)).catch()); | ||
} | ||
} | ||
getToken(forceRefresh) { | ||
if (!this.appCheck) { | ||
return new Promise((resolve, reject) => { | ||
// Support delayed initialization of FirebaseAppCheck. This allows our | ||
// customers to initialize the RTDB SDK before initializing Firebase | ||
// AppCheck and ensures that all requests are authenticated if a token | ||
// becomes available before the timoeout below expires. | ||
setTimeout(() => { | ||
if (this.appCheck) { | ||
this.getToken(forceRefresh).then(resolve, reject); | ||
} | ||
else { | ||
resolve(null); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
return this.appCheck.getToken(forceRefresh); | ||
} | ||
addTokenChangeListener(listener) { | ||
var _a; | ||
void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(appCheck => appCheck.addTokenListener(listener))); | ||
} | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
const Code = { | ||
@@ -59,3 +113,4 @@ OTHER: 'other', | ||
INVALID_ARGUMENT: 'invalid-argument', | ||
PARTIAL_ERROR: 'partial-error' | ||
PARTIAL_ERROR: 'partial-error', | ||
UNAUTHORIZED: 'unauthorized' | ||
}; | ||
@@ -127,2 +182,3 @@ /** An error returned by a DataConnect operation. */ | ||
*/ | ||
// @internal | ||
class FirebaseAuthProvider { | ||
@@ -170,3 +226,4 @@ constructor(_appName, _options, _authProvider) { | ||
.get() | ||
.then(auth => auth.removeAuthTokenListener(listener)); | ||
.then(auth => auth.removeAuthTokenListener(listener)) | ||
.catch(err => logError(err)); | ||
} | ||
@@ -411,3 +468,3 @@ } | ||
} | ||
return `${baseUrl}/v1alpha/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
return `${baseUrl}/v1beta/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
} | ||
@@ -440,3 +497,10 @@ function addToken(url, apiKey) { | ||
let connectFetch = globalThis.fetch; | ||
function dcFetch(url, body, { signal }, accessToken) { | ||
function getGoogApiClientValue(_isUsingGen) { | ||
let str = 'gl-js/ fire/' + SDK_VERSION; | ||
if (_isUsingGen) { | ||
str += ' web/gen'; | ||
} | ||
return str; | ||
} | ||
function dcFetch(url, body, { signal }, appId, accessToken, appCheckToken, _isUsingGen) { | ||
if (!connectFetch) { | ||
@@ -446,3 +510,4 @@ throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!'); | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
'Content-Type': 'application/json', | ||
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) | ||
}; | ||
@@ -452,2 +517,8 @@ if (accessToken) { | ||
} | ||
if (appId) { | ||
headers['x-firebase-gmpid'] = appId; | ||
} | ||
if (appCheckToken) { | ||
headers['X-Firebase-AppCheck'] = appCheckToken; | ||
} | ||
const bodyStr = JSON.stringify(body); | ||
@@ -460,5 +531,6 @@ logDebug(`Making request out to ${url} with body: ${bodyStr}`); | ||
signal | ||
}).catch(err => { | ||
throw new DataConnectError(Code.OTHER, "Failed to fetch: " + JSON.stringify(err)); | ||
}) | ||
.catch(err => { | ||
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); | ||
}) | ||
.then(async (response) => { | ||
@@ -472,5 +544,9 @@ let jsonResponse = null; | ||
} | ||
const message = getMessage(jsonResponse); | ||
if (response.status >= 400) { | ||
logError('Error while performing request: ' + JSON.stringify(jsonResponse)); | ||
throw new DataConnectError(Code.OTHER, JSON.stringify(jsonResponse)); | ||
if (response.status === 401) { | ||
throw new DataConnectError(Code.UNAUTHORIZED, message); | ||
} | ||
throw new DataConnectError(Code.OTHER, message); | ||
} | ||
@@ -488,2 +564,8 @@ return jsonResponse; | ||
} | ||
function getMessage(obj) { | ||
if ('message' in obj) { | ||
return obj.message; | ||
} | ||
return JSON.stringify(obj); | ||
} | ||
@@ -507,6 +589,9 @@ /** | ||
class RESTTransport { | ||
constructor(options, apiKey, authProvider, transportOptions) { | ||
var _a; | ||
constructor(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen = false) { | ||
var _a, _b; | ||
this.apiKey = apiKey; | ||
this.appId = appId; | ||
this.authProvider = authProvider; | ||
this.appCheckProvider = appCheckProvider; | ||
this._isUsingGen = _isUsingGen; | ||
this._host = ''; | ||
@@ -518,3 +603,4 @@ this._location = 'l'; | ||
this._accessToken = null; | ||
this._authInitialized = false; | ||
this._appCheckToken = null; | ||
this._lastToken = null; | ||
// TODO(mtewani): Update U to include shape of body defined in line 13. | ||
@@ -524,12 +610,11 @@ this.invokeQuery = (queryName, body) => { | ||
// TODO(mtewani): Update to proper value | ||
const withAuth = this.getWithAuth().then(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this._accessToken); | ||
}); | ||
const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen)); | ||
return { | ||
then: withAuth.then.bind(withAuth) | ||
then: withAuth.then.bind(withAuth), | ||
catch: withAuth.catch.bind(withAuth) | ||
}; | ||
@@ -539,3 +624,3 @@ }; | ||
const abortController = new AbortController(); | ||
const taskResult = this.getWithAuth().then(() => { | ||
const taskResult = this.withRetry(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), { | ||
@@ -545,3 +630,3 @@ name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
variables: body | ||
}, abortController, this._accessToken); | ||
}, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen); | ||
}); | ||
@@ -580,2 +665,7 @@ return { | ||
}); | ||
(_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(result => { | ||
const { token } = result; | ||
logDebug(`New App Check Token Available: ${token}`); | ||
this._appCheckToken = token; | ||
}); | ||
} | ||
@@ -602,22 +692,48 @@ get endpointUrl() { | ||
} | ||
getWithAuth() { | ||
async getWithAuth(forceToken = false) { | ||
var _a; | ||
let starterPromise = new Promise(resolve => resolve(this._accessToken)); | ||
if (!this._authInitialized) { | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ false) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
if (this.appCheckProvider) { | ||
this._appCheckToken = (_a = (await this.appCheckProvider.getToken())) === null || _a === void 0 ? void 0 : _a.token; | ||
} | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ forceToken) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
return starterPromise; | ||
} | ||
_setLastToken(lastToken) { | ||
this._lastToken = lastToken; | ||
} | ||
withRetry(promiseFactory, retry = false) { | ||
let isNewToken = false; | ||
return this.getWithAuth(retry) | ||
.then(res => { | ||
isNewToken = this._lastToken !== res; | ||
this._lastToken = res; | ||
return res; | ||
}) | ||
.then(promiseFactory) | ||
.catch(err => { | ||
// Only retry if the result is unauthorized and the last token isn't the same as the new one. | ||
if ('code' in err && | ||
err.code === Code.UNAUTHORIZED && | ||
!retry && | ||
isNewToken) { | ||
logDebug('Retrying due to unauthorized'); | ||
return this.withRetry(promiseFactory, true); | ||
} | ||
throw err; | ||
}); | ||
} | ||
} | ||
@@ -641,7 +757,14 @@ | ||
*/ | ||
function mutationRef(dcInstance, queryName, variables) { | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
* @returns `MutationRef` | ||
*/ | ||
function mutationRef(dcInstance, mutationName, variables) { | ||
dcInstance.setInitialized(); | ||
const ref = { | ||
dataConnect: dcInstance, | ||
name: queryName, | ||
name: mutationName, | ||
refType: MUTATION_STR, | ||
@@ -652,2 +775,5 @@ variables: variables | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
class MutationManager { | ||
@@ -670,2 +796,7 @@ constructor(_transport) { | ||
} | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
function executeMutation(mutationRef) { | ||
@@ -705,11 +836,17 @@ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
class DataConnect { | ||
// @internal | ||
constructor(app, | ||
// TODO(mtewani): Replace with _dataConnectOptions in the future | ||
dataConnectOptions, _authProvider) { | ||
dataConnectOptions, _authProvider, _appCheckProvider) { | ||
this.app = app; | ||
this.dataConnectOptions = dataConnectOptions; | ||
this._authProvider = _authProvider; | ||
this._appCheckProvider = _appCheckProvider; | ||
this.isEmulator = false; | ||
this.initialized = false; | ||
this._initialized = false; | ||
this._isUsingGeneratedSdk = false; | ||
if (typeof process !== 'undefined' && process.env) { | ||
@@ -724,2 +861,8 @@ const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; | ||
} | ||
// @internal | ||
_useGeneratedSdk() { | ||
if (!this._isUsingGeneratedSdk) { | ||
this._isUsingGeneratedSdk = true; | ||
} | ||
} | ||
_delete() { | ||
@@ -729,2 +872,3 @@ _removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); | ||
} | ||
// @internal | ||
getSettings() { | ||
@@ -735,4 +879,5 @@ const copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); | ||
} | ||
// @internal | ||
setInitialized() { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
return; | ||
@@ -747,4 +892,7 @@ } | ||
} | ||
this.initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider); | ||
if (this._appCheckProvider) { | ||
this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); | ||
} | ||
this._initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); | ||
if (this._transportOptions) { | ||
@@ -756,4 +904,5 @@ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); | ||
} | ||
// @internal | ||
enableEmulator(transportOptions) { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
logError('enableEmulator called after initialization'); | ||
@@ -766,2 +915,9 @@ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
function connectDataConnectEmulator(dc, host, port, sslEnabled = false) { | ||
@@ -781,3 +937,3 @@ dc.enableEmulator({ host, port, sslEnabled }); | ||
} | ||
if (!app) { | ||
if (!app || Object.keys(app).length === 0) { | ||
app = getApp(); | ||
@@ -796,5 +952,3 @@ } | ||
} | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
validateDCOptions(dcOptions); | ||
logDebug('Creating new DataConnect instance'); | ||
@@ -807,2 +961,25 @@ // Initialize with options. | ||
} | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
function validateDCOptions(dcOptions) { | ||
const fields = ['connector', 'location', 'service']; | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
fields.forEach(field => { | ||
if (dcOptions[field] === null || dcOptions[field] === undefined) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`); | ||
} | ||
}); | ||
return true; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
function terminate(dataConnect) { | ||
@@ -834,2 +1011,3 @@ return dataConnect._delete(); | ||
const authProvider = container.getProvider('auth-internal'); | ||
const appCheckProvider = container.getProvider('app-check-internal'); | ||
let newOpts = options; | ||
@@ -839,3 +1017,6 @@ if (settings) { | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider); | ||
if (!app.options.projectId) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); | ||
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); | ||
@@ -863,5 +1044,18 @@ registerVersion(name, version, variant); | ||
*/ | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
function executeQuery(queryRef) { | ||
return queryRef.dataConnect._queryManager.executeQuery(queryRef); | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @param initialCache initial cache to use for client hydration | ||
* @returns `QueryRef` | ||
*/ | ||
function queryRef(dcInstance, queryName, variables, initialCache) { | ||
@@ -877,2 +1071,7 @@ dcInstance.setInitialized(); | ||
} | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
function toQueryRef(serializedRef) { | ||
@@ -899,2 +1098,53 @@ const { refInfo: { name, variables, connectorConfig } } = serializedRef; | ||
*/ | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { | ||
let dcInstance; | ||
let realVars; | ||
if (dcOrVars && 'enableEmulator' in dcOrVars) { | ||
dcInstance = dcOrVars; | ||
realVars = vars; | ||
} | ||
else { | ||
dcInstance = getDataConnect(connectorConfig); | ||
realVars = dcOrVars; | ||
} | ||
if (!dcInstance || (!realVars && validateVars)) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); | ||
} | ||
return { dc: dcInstance, vars: realVars }; | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observerOrOnNext observer object or next function. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { | ||
@@ -938,3 +1188,3 @@ let ref; | ||
export { DataConnect, FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR, FirebaseAuthProvider, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef }; | ||
export { DataConnect, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef, validateArgs, validateDCOptions }; | ||
//# sourceMappingURL=index.esm2017.js.map |
@@ -8,3 +8,3 @@ import { __extends, __assign, __awaiter, __generator } from 'tslib'; | ||
var name = "@firebase/data-connect"; | ||
var version = "0.0.2-dataconnect-preview.877f8b7d0"; | ||
var version = "0.0.3-canary.beaa4dffb"; | ||
@@ -53,2 +53,59 @@ /** | ||
*/ | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
var AppCheckTokenProvider = /** @class */ (function () { | ||
function AppCheckTokenProvider(appName_, appCheckProvider) { | ||
var _this = this; | ||
this.appName_ = appName_; | ||
this.appCheckProvider = appCheckProvider; | ||
this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); | ||
if (!this.appCheck) { | ||
void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(function (appCheck) { return (_this.appCheck = appCheck); }).catch()); | ||
} | ||
} | ||
AppCheckTokenProvider.prototype.getToken = function (forceRefresh) { | ||
var _this = this; | ||
if (!this.appCheck) { | ||
return new Promise(function (resolve, reject) { | ||
// Support delayed initialization of FirebaseAppCheck. This allows our | ||
// customers to initialize the RTDB SDK before initializing Firebase | ||
// AppCheck and ensures that all requests are authenticated if a token | ||
// becomes available before the timoeout below expires. | ||
setTimeout(function () { | ||
if (_this.appCheck) { | ||
_this.getToken(forceRefresh).then(resolve, reject); | ||
} | ||
else { | ||
resolve(null); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
return this.appCheck.getToken(forceRefresh); | ||
}; | ||
AppCheckTokenProvider.prototype.addTokenChangeListener = function (listener) { | ||
var _a; | ||
void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(function (appCheck) { return appCheck.addTokenListener(listener); })); | ||
}; | ||
return AppCheckTokenProvider; | ||
}()); | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
var Code = { | ||
@@ -60,3 +117,4 @@ OTHER: 'other', | ||
INVALID_ARGUMENT: 'invalid-argument', | ||
PARTIAL_ERROR: 'partial-error' | ||
PARTIAL_ERROR: 'partial-error', | ||
UNAUTHORIZED: 'unauthorized' | ||
}; | ||
@@ -131,2 +189,3 @@ /** An error returned by a DataConnect operation. */ | ||
*/ | ||
// @internal | ||
var FirebaseAuthProvider = /** @class */ (function () { | ||
@@ -176,3 +235,4 @@ function FirebaseAuthProvider(_appName, _options, _authProvider) { | ||
.get() | ||
.then(function (auth) { return auth.removeAuthTokenListener(listener); }); | ||
.then(function (auth) { return auth.removeAuthTokenListener(listener); }) | ||
.catch(function (err) { return logError(err); }); | ||
}; | ||
@@ -420,3 +480,3 @@ return FirebaseAuthProvider; | ||
} | ||
return "".concat(baseUrl, "/v1alpha/projects/").concat(project, "/locations/").concat(location, "/services/").concat(service, "/connectors/").concat(connector); | ||
return "".concat(baseUrl, "/v1beta/projects/").concat(project, "/locations/").concat(location, "/services/").concat(service, "/connectors/").concat(connector); | ||
} | ||
@@ -449,3 +509,10 @@ function addToken(url, apiKey) { | ||
var connectFetch = globalThis.fetch; | ||
function dcFetch(url, body, _a, accessToken) { | ||
function getGoogApiClientValue(_isUsingGen) { | ||
var str = 'gl-js/ fire/' + SDK_VERSION; | ||
if (_isUsingGen) { | ||
str += ' web/gen'; | ||
} | ||
return str; | ||
} | ||
function dcFetch(url, body, _a, appId, accessToken, appCheckToken, _isUsingGen) { | ||
var _this = this; | ||
@@ -457,3 +524,4 @@ var signal = _a.signal; | ||
var headers = { | ||
'Content-Type': 'application/json' | ||
'Content-Type': 'application/json', | ||
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) | ||
}; | ||
@@ -463,2 +531,8 @@ if (accessToken) { | ||
} | ||
if (appId) { | ||
headers['x-firebase-gmpid'] = appId; | ||
} | ||
if (appCheckToken) { | ||
headers['X-Firebase-AppCheck'] = appCheckToken; | ||
} | ||
var bodyStr = JSON.stringify(body); | ||
@@ -471,7 +545,8 @@ logDebug("Making request out to ".concat(url, " with body: ").concat(bodyStr)); | ||
signal: signal | ||
}).catch(function (err) { | ||
throw new DataConnectError(Code.OTHER, "Failed to fetch: " + JSON.stringify(err)); | ||
}) | ||
.catch(function (err) { | ||
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); | ||
}) | ||
.then(function (response) { return __awaiter(_this, void 0, void 0, function () { | ||
var jsonResponse, e_1; | ||
var jsonResponse, e_1, message; | ||
return __generator(this, function (_a) { | ||
@@ -492,5 +567,9 @@ switch (_a.label) { | ||
case 4: | ||
message = getMessage(jsonResponse); | ||
if (response.status >= 400) { | ||
logError('Error while performing request: ' + JSON.stringify(jsonResponse)); | ||
throw new DataConnectError(Code.OTHER, JSON.stringify(jsonResponse)); | ||
if (response.status === 401) { | ||
throw new DataConnectError(Code.UNAUTHORIZED, message); | ||
} | ||
throw new DataConnectError(Code.OTHER, message); | ||
} | ||
@@ -510,2 +589,8 @@ return [2 /*return*/, jsonResponse]; | ||
} | ||
function getMessage(obj) { | ||
if ('message' in obj) { | ||
return obj.message; | ||
} | ||
return JSON.stringify(obj); | ||
} | ||
@@ -529,7 +614,11 @@ /** | ||
var RESTTransport = /** @class */ (function () { | ||
function RESTTransport(options, apiKey, authProvider, transportOptions) { | ||
function RESTTransport(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen) { | ||
if (_isUsingGen === void 0) { _isUsingGen = false; } | ||
var _this = this; | ||
var _a; | ||
var _a, _b; | ||
this.apiKey = apiKey; | ||
this.appId = appId; | ||
this.authProvider = authProvider; | ||
this.appCheckProvider = appCheckProvider; | ||
this._isUsingGen = _isUsingGen; | ||
this._host = ''; | ||
@@ -541,3 +630,4 @@ this._location = 'l'; | ||
this._accessToken = null; | ||
this._authInitialized = false; | ||
this._appCheckToken = null; | ||
this._lastToken = null; | ||
// TODO(mtewani): Update U to include shape of body defined in line 13. | ||
@@ -547,3 +637,3 @@ this.invokeQuery = function (queryName, body) { | ||
// TODO(mtewani): Update to proper value | ||
var withAuth = _this.getWithAuth().then(function () { | ||
var withAuth = _this.withRetry(function () { | ||
return dcFetch(addToken("".concat(_this.endpointUrl, ":executeQuery"), _this.apiKey), { | ||
@@ -554,6 +644,7 @@ name: "projects/".concat(_this._project, "/locations/").concat(_this._location, "/services/").concat(_this._serviceName, "/connectors/").concat(_this._connectorName), | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, _this._accessToken); | ||
abortController, _this.appId, _this._accessToken, _this._appCheckToken, _this._isUsingGen); | ||
}); | ||
return { | ||
then: withAuth.then.bind(withAuth) | ||
then: withAuth.then.bind(withAuth), | ||
catch: withAuth.catch.bind(withAuth) | ||
}; | ||
@@ -563,3 +654,3 @@ }; | ||
var abortController = new AbortController(); | ||
var taskResult = _this.getWithAuth().then(function () { | ||
var taskResult = _this.withRetry(function () { | ||
return dcFetch(addToken("".concat(_this.endpointUrl, ":executeMutation"), _this.apiKey), { | ||
@@ -569,3 +660,3 @@ name: "projects/".concat(_this._project, "/locations/").concat(_this._location, "/services/").concat(_this._serviceName, "/connectors/").concat(_this._connectorName), | ||
variables: body | ||
}, abortController, _this._accessToken); | ||
}, abortController, _this.appId, _this._accessToken, _this._appCheckToken, _this._isUsingGen); | ||
}); | ||
@@ -604,2 +695,7 @@ return { | ||
}); | ||
(_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(function (result) { | ||
var token = result.token; | ||
logDebug("New App Check Token Available: ".concat(token)); | ||
_this._appCheckToken = token; | ||
}); | ||
} | ||
@@ -630,24 +726,65 @@ Object.defineProperty(RESTTransport.prototype, "endpointUrl", { | ||
}; | ||
RESTTransport.prototype.getWithAuth = function () { | ||
RESTTransport.prototype.getWithAuth = function (forceToken) { | ||
var _a; | ||
if (forceToken === void 0) { forceToken = false; } | ||
return __awaiter(this, void 0, void 0, function () { | ||
var starterPromise, _b; | ||
var _this = this; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
starterPromise = new Promise(function (resolve) { | ||
return resolve(_this._accessToken); | ||
}); | ||
if (!this.appCheckProvider) return [3 /*break*/, 2]; | ||
_b = this; | ||
return [4 /*yield*/, this.appCheckProvider.getToken()]; | ||
case 1: | ||
_b._appCheckToken = (_a = (_c.sent())) === null || _a === void 0 ? void 0 : _a.token; | ||
_c.label = 2; | ||
case 2: | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ forceToken) | ||
.then(function (data) { | ||
if (!data) { | ||
return null; | ||
} | ||
_this._accessToken = data.accessToken; | ||
return _this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(function (resolve) { return resolve(''); }); | ||
} | ||
return [2 /*return*/, starterPromise]; | ||
} | ||
}); | ||
}); | ||
}; | ||
RESTTransport.prototype._setLastToken = function (lastToken) { | ||
this._lastToken = lastToken; | ||
}; | ||
RESTTransport.prototype.withRetry = function (promiseFactory, retry) { | ||
var _this = this; | ||
var starterPromise = new Promise(function (resolve) { | ||
return resolve(_this._accessToken); | ||
if (retry === void 0) { retry = false; } | ||
var isNewToken = false; | ||
return this.getWithAuth(retry) | ||
.then(function (res) { | ||
isNewToken = _this._lastToken !== res; | ||
_this._lastToken = res; | ||
return res; | ||
}) | ||
.then(promiseFactory) | ||
.catch(function (err) { | ||
// Only retry if the result is unauthorized and the last token isn't the same as the new one. | ||
if ('code' in err && | ||
err.code === Code.UNAUTHORIZED && | ||
!retry && | ||
isNewToken) { | ||
logDebug('Retrying due to unauthorized'); | ||
return _this.withRetry(promiseFactory, true); | ||
} | ||
throw err; | ||
}); | ||
if (!this._authInitialized) { | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ false) | ||
.then(function (data) { | ||
if (!data) { | ||
return null; | ||
} | ||
_this._accessToken = data.accessToken; | ||
return _this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(function (resolve) { return resolve(''); }); | ||
} | ||
} | ||
return starterPromise; | ||
}; | ||
@@ -673,7 +810,14 @@ return RESTTransport; | ||
*/ | ||
function mutationRef(dcInstance, queryName, variables) { | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
* @returns `MutationRef` | ||
*/ | ||
function mutationRef(dcInstance, mutationName, variables) { | ||
dcInstance.setInitialized(); | ||
var ref = { | ||
dataConnect: dcInstance, | ||
name: queryName, | ||
name: mutationName, | ||
refType: MUTATION_STR, | ||
@@ -684,2 +828,5 @@ variables: variables | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
var MutationManager = /** @class */ (function () { | ||
@@ -706,2 +853,7 @@ function MutationManager(_transport) { | ||
}()); | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
function executeMutation(mutationRef) { | ||
@@ -741,11 +893,17 @@ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
var DataConnect = /** @class */ (function () { | ||
// @internal | ||
function DataConnect(app, | ||
// TODO(mtewani): Replace with _dataConnectOptions in the future | ||
dataConnectOptions, _authProvider) { | ||
dataConnectOptions, _authProvider, _appCheckProvider) { | ||
this.app = app; | ||
this.dataConnectOptions = dataConnectOptions; | ||
this._authProvider = _authProvider; | ||
this._appCheckProvider = _appCheckProvider; | ||
this.isEmulator = false; | ||
this.initialized = false; | ||
this._initialized = false; | ||
this._isUsingGeneratedSdk = false; | ||
if (typeof process !== 'undefined' && process.env) { | ||
@@ -760,2 +918,8 @@ var host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; | ||
} | ||
// @internal | ||
DataConnect.prototype._useGeneratedSdk = function () { | ||
if (!this._isUsingGeneratedSdk) { | ||
this._isUsingGeneratedSdk = true; | ||
} | ||
}; | ||
DataConnect.prototype._delete = function () { | ||
@@ -765,2 +929,3 @@ _removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); | ||
}; | ||
// @internal | ||
DataConnect.prototype.getSettings = function () { | ||
@@ -771,4 +936,5 @@ var copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); | ||
}; | ||
// @internal | ||
DataConnect.prototype.setInitialized = function () { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
return; | ||
@@ -783,4 +949,7 @@ } | ||
} | ||
this.initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider); | ||
if (this._appCheckProvider) { | ||
this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); | ||
} | ||
this._initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); | ||
if (this._transportOptions) { | ||
@@ -792,4 +961,5 @@ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); | ||
}; | ||
// @internal | ||
DataConnect.prototype.enableEmulator = function (transportOptions) { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
logError('enableEmulator called after initialization'); | ||
@@ -803,2 +973,9 @@ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); | ||
}()); | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
function connectDataConnectEmulator(dc, host, port, sslEnabled) { | ||
@@ -819,3 +996,3 @@ if (sslEnabled === void 0) { sslEnabled = false; } | ||
} | ||
if (!app) { | ||
if (!app || Object.keys(app).length === 0) { | ||
app = getApp(); | ||
@@ -834,5 +1011,3 @@ } | ||
} | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
validateDCOptions(dcOptions); | ||
logDebug('Creating new DataConnect instance'); | ||
@@ -845,2 +1020,25 @@ // Initialize with options. | ||
} | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
function validateDCOptions(dcOptions) { | ||
var fields = ['connector', 'location', 'service']; | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
fields.forEach(function (field) { | ||
if (dcOptions[field] === null || dcOptions[field] === undefined) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, "".concat(field, " Required")); | ||
} | ||
}); | ||
return true; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
function terminate(dataConnect) { | ||
@@ -857,2 +1055,3 @@ return dataConnect._delete(); | ||
var authProvider = container.getProvider('auth-internal'); | ||
var appCheckProvider = container.getProvider('app-check-internal'); | ||
var newOpts = options; | ||
@@ -862,3 +1061,6 @@ if (settings) { | ||
} | ||
return new DataConnect(app, __assign(__assign({}, newOpts), { projectId: app.options.projectId }), authProvider); | ||
if (!app.options.projectId) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); | ||
} | ||
return new DataConnect(app, __assign(__assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); | ||
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); | ||
@@ -886,5 +1088,18 @@ registerVersion(name, version, variant); | ||
*/ | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
function executeQuery(queryRef) { | ||
return queryRef.dataConnect._queryManager.executeQuery(queryRef); | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @param initialCache initial cache to use for client hydration | ||
* @returns `QueryRef` | ||
*/ | ||
function queryRef(dcInstance, queryName, variables, initialCache) { | ||
@@ -900,2 +1115,7 @@ dcInstance.setInitialized(); | ||
} | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
function toQueryRef(serializedRef) { | ||
@@ -922,2 +1142,53 @@ var _a = serializedRef.refInfo, name = _a.name, variables = _a.variables, connectorConfig = _a.connectorConfig; | ||
*/ | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { | ||
var dcInstance; | ||
var realVars; | ||
if (dcOrVars && 'enableEmulator' in dcOrVars) { | ||
dcInstance = dcOrVars; | ||
realVars = vars; | ||
} | ||
else { | ||
dcInstance = getDataConnect(connectorConfig); | ||
realVars = dcOrVars; | ||
} | ||
if (!dcInstance || (!realVars && validateVars)) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); | ||
} | ||
return { dc: dcInstance, vars: realVars }; | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observerOrOnNext observer object or next function. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { | ||
@@ -961,3 +1232,3 @@ var ref; | ||
export { DataConnect, FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR, FirebaseAuthProvider, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef }; | ||
export { DataConnect, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef, validateArgs, validateDCOptions }; | ||
//# sourceMappingURL=index.esm5.js.map |
@@ -33,3 +33,4 @@ 'use strict'; | ||
INVALID_ARGUMENT: 'invalid-argument', | ||
PARTIAL_ERROR: 'partial-error' | ||
PARTIAL_ERROR: 'partial-error', | ||
UNAUTHORIZED: 'unauthorized' | ||
}; | ||
@@ -134,3 +135,10 @@ /** An error returned by a DataConnect operation. */ | ||
} | ||
function dcFetch(url, body, _a, accessToken) { | ||
function getGoogApiClientValue(_isUsingGen) { | ||
var str = 'gl-js/ fire/' + SDK_VERSION; | ||
if (_isUsingGen) { | ||
str += ' web/gen'; | ||
} | ||
return str; | ||
} | ||
function dcFetch(url, body, _a, appId, accessToken, appCheckToken, _isUsingGen) { | ||
var _this = this; | ||
@@ -142,3 +150,4 @@ var signal = _a.signal; | ||
var headers = { | ||
'Content-Type': 'application/json' | ||
'Content-Type': 'application/json', | ||
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) | ||
}; | ||
@@ -148,2 +157,8 @@ if (accessToken) { | ||
} | ||
if (appId) { | ||
headers['x-firebase-gmpid'] = appId; | ||
} | ||
if (appCheckToken) { | ||
headers['X-Firebase-AppCheck'] = appCheckToken; | ||
} | ||
var bodyStr = JSON.stringify(body); | ||
@@ -156,7 +171,8 @@ logDebug("Making request out to ".concat(url, " with body: ").concat(bodyStr)); | ||
signal: signal | ||
}).catch(function (err) { | ||
throw new DataConnectError(Code.OTHER, "Failed to fetch: " + JSON.stringify(err)); | ||
}) | ||
.catch(function (err) { | ||
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); | ||
}) | ||
.then(function (response) { return tslib.__awaiter(_this, void 0, void 0, function () { | ||
var jsonResponse, e_1; | ||
var jsonResponse, e_1, message; | ||
return tslib.__generator(this, function (_a) { | ||
@@ -177,5 +193,9 @@ switch (_a.label) { | ||
case 4: | ||
message = getMessage(jsonResponse); | ||
if (response.status >= 400) { | ||
logError('Error while performing request: ' + JSON.stringify(jsonResponse)); | ||
throw new DataConnectError(Code.OTHER, JSON.stringify(jsonResponse)); | ||
if (response.status === 401) { | ||
throw new DataConnectError(Code.UNAUTHORIZED, message); | ||
} | ||
throw new DataConnectError(Code.OTHER, message); | ||
} | ||
@@ -195,5 +215,11 @@ return [2 /*return*/, jsonResponse]; | ||
} | ||
function getMessage(obj) { | ||
if ('message' in obj) { | ||
return obj.message; | ||
} | ||
return JSON.stringify(obj); | ||
} | ||
var name = "@firebase/data-connect"; | ||
var version = "0.0.2-dataconnect-preview.877f8b7d0"; | ||
var version = "0.0.3-canary.beaa4dffb"; | ||
@@ -216,2 +242,60 @@ /** | ||
*/ | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
var AppCheckTokenProvider = /** @class */ (function () { | ||
function AppCheckTokenProvider(appName_, appCheckProvider) { | ||
var _this = this; | ||
this.appName_ = appName_; | ||
this.appCheckProvider = appCheckProvider; | ||
this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); | ||
if (!this.appCheck) { | ||
void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(function (appCheck) { return (_this.appCheck = appCheck); }).catch()); | ||
} | ||
} | ||
AppCheckTokenProvider.prototype.getToken = function (forceRefresh) { | ||
var _this = this; | ||
if (!this.appCheck) { | ||
return new Promise(function (resolve, reject) { | ||
// Support delayed initialization of FirebaseAppCheck. This allows our | ||
// customers to initialize the RTDB SDK before initializing Firebase | ||
// AppCheck and ensures that all requests are authenticated if a token | ||
// becomes available before the timoeout below expires. | ||
setTimeout(function () { | ||
if (_this.appCheck) { | ||
_this.getToken(forceRefresh).then(resolve, reject); | ||
} | ||
else { | ||
resolve(null); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
return this.appCheck.getToken(forceRefresh); | ||
}; | ||
AppCheckTokenProvider.prototype.addTokenChangeListener = function (listener) { | ||
var _a; | ||
void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(function (appCheck) { return appCheck.addTokenListener(listener); })); | ||
}; | ||
return AppCheckTokenProvider; | ||
}()); | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
// @internal | ||
var FirebaseAuthProvider = /** @class */ (function () { | ||
@@ -261,3 +345,4 @@ function FirebaseAuthProvider(_appName, _options, _authProvider) { | ||
.get() | ||
.then(function (auth) { return auth.removeAuthTokenListener(listener); }); | ||
.then(function (auth) { return auth.removeAuthTokenListener(listener); }) | ||
.catch(function (err) { return logError(err); }); | ||
}; | ||
@@ -505,3 +590,3 @@ return FirebaseAuthProvider; | ||
} | ||
return "".concat(baseUrl, "/v1alpha/projects/").concat(project, "/locations/").concat(location, "/services/").concat(service, "/connectors/").concat(connector); | ||
return "".concat(baseUrl, "/v1beta/projects/").concat(project, "/locations/").concat(location, "/services/").concat(service, "/connectors/").concat(connector); | ||
} | ||
@@ -534,7 +619,11 @@ function addToken(url, apiKey) { | ||
var RESTTransport = /** @class */ (function () { | ||
function RESTTransport(options, apiKey, authProvider, transportOptions) { | ||
function RESTTransport(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen) { | ||
if (_isUsingGen === void 0) { _isUsingGen = false; } | ||
var _this = this; | ||
var _a; | ||
var _a, _b; | ||
this.apiKey = apiKey; | ||
this.appId = appId; | ||
this.authProvider = authProvider; | ||
this.appCheckProvider = appCheckProvider; | ||
this._isUsingGen = _isUsingGen; | ||
this._host = ''; | ||
@@ -546,3 +635,4 @@ this._location = 'l'; | ||
this._accessToken = null; | ||
this._authInitialized = false; | ||
this._appCheckToken = null; | ||
this._lastToken = null; | ||
// TODO(mtewani): Update U to include shape of body defined in line 13. | ||
@@ -552,3 +642,3 @@ this.invokeQuery = function (queryName, body) { | ||
// TODO(mtewani): Update to proper value | ||
var withAuth = _this.getWithAuth().then(function () { | ||
var withAuth = _this.withRetry(function () { | ||
return dcFetch(addToken("".concat(_this.endpointUrl, ":executeQuery"), _this.apiKey), { | ||
@@ -559,6 +649,7 @@ name: "projects/".concat(_this._project, "/locations/").concat(_this._location, "/services/").concat(_this._serviceName, "/connectors/").concat(_this._connectorName), | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, _this._accessToken); | ||
abortController, _this.appId, _this._accessToken, _this._appCheckToken, _this._isUsingGen); | ||
}); | ||
return { | ||
then: withAuth.then.bind(withAuth) | ||
then: withAuth.then.bind(withAuth), | ||
catch: withAuth.catch.bind(withAuth) | ||
}; | ||
@@ -568,3 +659,3 @@ }; | ||
var abortController = new AbortController(); | ||
var taskResult = _this.getWithAuth().then(function () { | ||
var taskResult = _this.withRetry(function () { | ||
return dcFetch(addToken("".concat(_this.endpointUrl, ":executeMutation"), _this.apiKey), { | ||
@@ -574,3 +665,3 @@ name: "projects/".concat(_this._project, "/locations/").concat(_this._location, "/services/").concat(_this._serviceName, "/connectors/").concat(_this._connectorName), | ||
variables: body | ||
}, abortController, _this._accessToken); | ||
}, abortController, _this.appId, _this._accessToken, _this._appCheckToken, _this._isUsingGen); | ||
}); | ||
@@ -609,2 +700,7 @@ return { | ||
}); | ||
(_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(function (result) { | ||
var token = result.token; | ||
logDebug("New App Check Token Available: ".concat(token)); | ||
_this._appCheckToken = token; | ||
}); | ||
} | ||
@@ -635,24 +731,65 @@ Object.defineProperty(RESTTransport.prototype, "endpointUrl", { | ||
}; | ||
RESTTransport.prototype.getWithAuth = function () { | ||
RESTTransport.prototype.getWithAuth = function (forceToken) { | ||
var _a; | ||
if (forceToken === void 0) { forceToken = false; } | ||
return tslib.__awaiter(this, void 0, void 0, function () { | ||
var starterPromise, _b; | ||
var _this = this; | ||
return tslib.__generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
starterPromise = new Promise(function (resolve) { | ||
return resolve(_this._accessToken); | ||
}); | ||
if (!this.appCheckProvider) return [3 /*break*/, 2]; | ||
_b = this; | ||
return [4 /*yield*/, this.appCheckProvider.getToken()]; | ||
case 1: | ||
_b._appCheckToken = (_a = (_c.sent())) === null || _a === void 0 ? void 0 : _a.token; | ||
_c.label = 2; | ||
case 2: | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ forceToken) | ||
.then(function (data) { | ||
if (!data) { | ||
return null; | ||
} | ||
_this._accessToken = data.accessToken; | ||
return _this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(function (resolve) { return resolve(''); }); | ||
} | ||
return [2 /*return*/, starterPromise]; | ||
} | ||
}); | ||
}); | ||
}; | ||
RESTTransport.prototype._setLastToken = function (lastToken) { | ||
this._lastToken = lastToken; | ||
}; | ||
RESTTransport.prototype.withRetry = function (promiseFactory, retry) { | ||
var _this = this; | ||
var starterPromise = new Promise(function (resolve) { | ||
return resolve(_this._accessToken); | ||
if (retry === void 0) { retry = false; } | ||
var isNewToken = false; | ||
return this.getWithAuth(retry) | ||
.then(function (res) { | ||
isNewToken = _this._lastToken !== res; | ||
_this._lastToken = res; | ||
return res; | ||
}) | ||
.then(promiseFactory) | ||
.catch(function (err) { | ||
// Only retry if the result is unauthorized and the last token isn't the same as the new one. | ||
if ('code' in err && | ||
err.code === Code.UNAUTHORIZED && | ||
!retry && | ||
isNewToken) { | ||
logDebug('Retrying due to unauthorized'); | ||
return _this.withRetry(promiseFactory, true); | ||
} | ||
throw err; | ||
}); | ||
if (!this._authInitialized) { | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ false) | ||
.then(function (data) { | ||
if (!data) { | ||
return null; | ||
} | ||
_this._accessToken = data.accessToken; | ||
return _this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(function (resolve) { return resolve(''); }); | ||
} | ||
} | ||
return starterPromise; | ||
}; | ||
@@ -678,7 +815,14 @@ return RESTTransport; | ||
*/ | ||
function mutationRef(dcInstance, queryName, variables) { | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
* @returns `MutationRef` | ||
*/ | ||
function mutationRef(dcInstance, mutationName, variables) { | ||
dcInstance.setInitialized(); | ||
var ref = { | ||
dataConnect: dcInstance, | ||
name: queryName, | ||
name: mutationName, | ||
refType: MUTATION_STR, | ||
@@ -689,2 +833,5 @@ variables: variables | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
var MutationManager = /** @class */ (function () { | ||
@@ -711,2 +858,7 @@ function MutationManager(_transport) { | ||
}()); | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
function executeMutation(mutationRef) { | ||
@@ -746,11 +898,17 @@ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
var DataConnect = /** @class */ (function () { | ||
// @internal | ||
function DataConnect(app, | ||
// TODO(mtewani): Replace with _dataConnectOptions in the future | ||
dataConnectOptions, _authProvider) { | ||
dataConnectOptions, _authProvider, _appCheckProvider) { | ||
this.app = app; | ||
this.dataConnectOptions = dataConnectOptions; | ||
this._authProvider = _authProvider; | ||
this._appCheckProvider = _appCheckProvider; | ||
this.isEmulator = false; | ||
this.initialized = false; | ||
this._initialized = false; | ||
this._isUsingGeneratedSdk = false; | ||
if (typeof process !== 'undefined' && process.env) { | ||
@@ -765,2 +923,8 @@ var host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; | ||
} | ||
// @internal | ||
DataConnect.prototype._useGeneratedSdk = function () { | ||
if (!this._isUsingGeneratedSdk) { | ||
this._isUsingGeneratedSdk = true; | ||
} | ||
}; | ||
DataConnect.prototype._delete = function () { | ||
@@ -770,2 +934,3 @@ app._removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); | ||
}; | ||
// @internal | ||
DataConnect.prototype.getSettings = function () { | ||
@@ -776,4 +941,5 @@ var copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); | ||
}; | ||
// @internal | ||
DataConnect.prototype.setInitialized = function () { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
return; | ||
@@ -788,4 +954,7 @@ } | ||
} | ||
this.initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider); | ||
if (this._appCheckProvider) { | ||
this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); | ||
} | ||
this._initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); | ||
if (this._transportOptions) { | ||
@@ -797,4 +966,5 @@ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); | ||
}; | ||
// @internal | ||
DataConnect.prototype.enableEmulator = function (transportOptions) { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
logError('enableEmulator called after initialization'); | ||
@@ -808,2 +978,9 @@ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); | ||
}()); | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
function connectDataConnectEmulator(dc, host, port, sslEnabled) { | ||
@@ -824,3 +1001,3 @@ if (sslEnabled === void 0) { sslEnabled = false; } | ||
} | ||
if (!app$1) { | ||
if (!app$1 || Object.keys(app$1).length === 0) { | ||
app$1 = app.getApp(); | ||
@@ -839,5 +1016,3 @@ } | ||
} | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
validateDCOptions(dcOptions); | ||
logDebug('Creating new DataConnect instance'); | ||
@@ -850,2 +1025,25 @@ // Initialize with options. | ||
} | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
function validateDCOptions(dcOptions) { | ||
var fields = ['connector', 'location', 'service']; | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
fields.forEach(function (field) { | ||
if (dcOptions[field] === null || dcOptions[field] === undefined) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, "".concat(field, " Required")); | ||
} | ||
}); | ||
return true; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
function terminate(dataConnect) { | ||
@@ -862,2 +1060,3 @@ return dataConnect._delete(); | ||
var authProvider = container.getProvider('auth-internal'); | ||
var appCheckProvider = container.getProvider('app-check-internal'); | ||
var newOpts = options; | ||
@@ -867,3 +1066,6 @@ if (settings) { | ||
} | ||
return new DataConnect(app, tslib.__assign(tslib.__assign({}, newOpts), { projectId: app.options.projectId }), authProvider); | ||
if (!app.options.projectId) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); | ||
} | ||
return new DataConnect(app, tslib.__assign(tslib.__assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); | ||
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); | ||
@@ -891,5 +1093,18 @@ app.registerVersion(name, version, variant); | ||
*/ | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
function executeQuery(queryRef) { | ||
return queryRef.dataConnect._queryManager.executeQuery(queryRef); | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @param initialCache initial cache to use for client hydration | ||
* @returns `QueryRef` | ||
*/ | ||
function queryRef(dcInstance, queryName, variables, initialCache) { | ||
@@ -905,2 +1120,7 @@ dcInstance.setInitialized(); | ||
} | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
function toQueryRef(serializedRef) { | ||
@@ -927,2 +1147,53 @@ var _a = serializedRef.refInfo, name = _a.name, variables = _a.variables, connectorConfig = _a.connectorConfig; | ||
*/ | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { | ||
var dcInstance; | ||
var realVars; | ||
if (dcOrVars && 'enableEmulator' in dcOrVars) { | ||
dcInstance = dcOrVars; | ||
realVars = vars; | ||
} | ||
else { | ||
dcInstance = getDataConnect(connectorConfig); | ||
realVars = dcOrVars; | ||
} | ||
if (!dcInstance || (!realVars && validateVars)) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); | ||
} | ||
return { dc: dcInstance, vars: realVars }; | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observerOrOnNext observer object or next function. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { | ||
@@ -979,4 +1250,2 @@ var ref; | ||
exports.DataConnect = DataConnect; | ||
exports.FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR; | ||
exports.FirebaseAuthProvider = FirebaseAuthProvider; | ||
exports.MUTATION_STR = MUTATION_STR; | ||
@@ -998,2 +1267,4 @@ exports.MutationManager = MutationManager; | ||
exports.toQueryRef = toQueryRef; | ||
exports.validateArgs = validateArgs; | ||
exports.validateDCOptions = validateDCOptions; | ||
//# sourceMappingURL=index.node.cjs.js.map |
@@ -7,2 +7,5 @@ /** | ||
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; | ||
import { AppCheckTokenListener } from '@firebase/app-check-interop-types'; | ||
import { AppCheckTokenResult } from '@firebase/app-check-interop-types'; | ||
import { FirebaseApp } from '@firebase/app'; | ||
@@ -12,9 +15,21 @@ import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; | ||
import { FirebaseError } from '@firebase/util'; | ||
import { FirebaseOptions } from '@firebase/app'; | ||
import { LogLevelString } from '@firebase/logger'; | ||
import { Provider } from '@firebase/component'; | ||
export declare type AuthTokenListener = (token: string | null) => void; | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
declare class AppCheckTokenProvider { | ||
private appName_; | ||
private appCheckProvider?; | ||
private appCheck?; | ||
constructor(appName_: string, appCheckProvider?: Provider<AppCheckInternalComponentName>); | ||
getToken(forceRefresh?: boolean): Promise<AppCheckTokenResult>; | ||
addTokenChangeListener(listener: AppCheckTokenListener): void; | ||
} | ||
export declare interface AuthTokenProvider { | ||
declare type AuthTokenListener = (token: string | null) => void; | ||
declare interface AuthTokenProvider { | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
@@ -30,4 +45,14 @@ addTokenChangeListener(listener: AuthTokenListener): void; | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
export declare function connectDataConnectEmulator(dc: DataConnect, host: string, port?: number, sslEnabled?: boolean): void; | ||
/** | ||
* Connector Config for calling Data Connect backend. | ||
*/ | ||
export declare interface ConnectorConfig { | ||
@@ -39,2 +64,5 @@ location: string; | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
export declare class DataConnect { | ||
@@ -44,6 +72,7 @@ readonly app: FirebaseApp; | ||
private readonly _authProvider; | ||
private readonly _appCheckProvider; | ||
_queryManager: QueryManager; | ||
_mutationManager: MutationManager; | ||
isEmulator: boolean; | ||
initialized: boolean; | ||
_initialized: boolean; | ||
private _transport; | ||
@@ -53,3 +82,6 @@ private _transportClass; | ||
private _authTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
_isUsingGeneratedSdk: boolean; | ||
private _appCheckTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>, _appCheckProvider: Provider<AppCheckInternalComponentName>); | ||
_useGeneratedSdk(): void; | ||
_delete(): Promise<void>; | ||
@@ -85,4 +117,7 @@ getSettings(): ConnectorConfig; | ||
declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error'; | ||
declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error' | 'unauthorized'; | ||
/** | ||
* DataConnectOptions including project id | ||
*/ | ||
export declare interface DataConnectOptions extends ConnectorConfig { | ||
@@ -96,2 +131,5 @@ projectId: string; | ||
/** | ||
* Representation of user provided subscription options. | ||
*/ | ||
export declare interface DataConnectSubscription<Data, Variables> { | ||
@@ -103,2 +141,5 @@ userCallback: OnResultSubscription<Data, Variables>; | ||
/** | ||
* @internal | ||
*/ | ||
export declare interface DataConnectTransport { | ||
@@ -119,21 +160,27 @@ invokeQuery<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
export declare function executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
export declare function executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
export declare const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = "FIREBASE_DATA_CONNECT_EMULATOR_HOST"; | ||
export declare class FirebaseAuthProvider implements AuthTokenProvider { | ||
private _appName; | ||
private _options; | ||
private _authProvider; | ||
private _auth; | ||
constructor(_appName: string, _options: FirebaseOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
addTokenChangeListener(listener: AuthTokenListener): void; | ||
removeTokenChangeListener(listener: (token: string | null) => void): void; | ||
} | ||
/** | ||
* Initialize DataConnect instance | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(options: ConnectorConfig): DataConnect; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param app FirebaseApp to initialize to. | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(app: FirebaseApp, options: ConnectorConfig): DataConnect; | ||
@@ -143,2 +190,5 @@ | ||
/** | ||
* @internal | ||
*/ | ||
export declare class MutationManager { | ||
@@ -151,2 +201,5 @@ private _transport; | ||
/** | ||
* Mutation return value from `executeMutation` | ||
*/ | ||
export declare interface MutationPromise<Data, Variables> extends PromiseLike<MutationResult<Data, Variables>> { | ||
@@ -159,9 +212,20 @@ } | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, queryName: string): MutationRef<Data, undefined>; | ||
/** | ||
* Creates a `MutationRef` | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
*/ | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, mutationName: string): MutationRef<Data, undefined>; | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
*/ | ||
export declare function mutationRef<Data, Variables>(dcInstance: DataConnect, mutationName: string, variables: Variables): MutationRef<Data, Variables>; | ||
export declare interface MutationResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Mutation Result from `executeMutation` | ||
*/ | ||
export declare interface MutationResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -171,6 +235,15 @@ ref: MutationRef<Data, Variables>; | ||
/** | ||
* `OnCompleteSubscription` | ||
*/ | ||
export declare type OnCompleteSubscription = () => void; | ||
/** | ||
* Signature for `OnErrorSubscription` for `subscribe` | ||
*/ | ||
export declare type OnErrorSubscription = (err?: DataConnectError) => void; | ||
/** | ||
* Signature for `OnResultSubscription` for `subscribe` | ||
*/ | ||
export declare type OnResultSubscription<Data, Variables> = (res: QueryResult<Data, Variables>) => void; | ||
@@ -191,2 +264,7 @@ | ||
declare interface ParsedArgs<Variables> { | ||
dc: DataConnect; | ||
vars: Variables; | ||
} | ||
/** | ||
@@ -206,3 +284,3 @@ * | ||
constructor(transport: DataConnectTransport); | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<unknown, unknown>; | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<Data, Variables>; | ||
addSubscription<Data, Variables>(queryRef: OperationRef<Data, Variables>, onResultCallback: OnResultSubscription<Data, Variables>, onErrorCallback?: OnErrorSubscription, initialCache?: OpResult<Data>): () => void; | ||
@@ -213,5 +291,11 @@ executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
/** | ||
* Promise returned from `executeQuery` | ||
*/ | ||
export declare interface QueryPromise<Data, Variables> extends PromiseLike<QueryResult<Data, Variables>> { | ||
} | ||
/** | ||
* QueryRef object | ||
*/ | ||
export declare interface QueryRef<Data, Variables> extends OperationRef<Data, Variables> { | ||
@@ -221,9 +305,22 @@ refType: typeof QUERY_STR; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data>(dcInstance: DataConnect, queryName: string): QueryRef<Data, undefined>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data, Variables>(dcInstance: DataConnect, queryName: string, variables: Variables): QueryRef<Data, Variables>; | ||
export declare interface QueryResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Result of `executeQuery` | ||
*/ | ||
export declare interface QueryResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -234,2 +331,5 @@ ref: QueryRef<Data, Variables>; | ||
/** | ||
* Signature for unsubscribe from `subscribe` | ||
*/ | ||
export declare type QueryUnsubscribe = () => void; | ||
@@ -239,2 +339,5 @@ | ||
/** | ||
* Serialized RefInfo as a result of `QueryResult.toJSON().refInfo` | ||
*/ | ||
export declare interface RefInfo<Variables> { | ||
@@ -246,7 +349,5 @@ name: string; | ||
export declare interface Sender<T> { | ||
abort: () => void; | ||
send: () => Promise<T>; | ||
} | ||
/** | ||
* Serialized Ref as a result of `QueryResult.toJSON()` | ||
*/ | ||
export declare interface SerializedRef<Data, Variables> extends OpResult<Data> { | ||
@@ -263,14 +364,22 @@ refInfo: RefInfo<Variables>; | ||
/** | ||
* | ||
* @public | ||
* @param queryRef | ||
* @param onResult | ||
* @param onErr | ||
* @param initialCache | ||
* @returns | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observer observer object to use for subscribing. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, observer: SubscriptionOptions<Data, Variables>): QueryUnsubscribe; | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param onNext Callback to call when result comes back. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, onNext: OnResultSubscription<Data, Variables>, onError?: OnErrorSubscription, onComplete?: OnCompleteSubscription): QueryUnsubscribe; | ||
/** | ||
* Representation of full observer options in `subscribe` | ||
*/ | ||
export declare interface SubscriptionOptions<Data, Variables> { | ||
@@ -282,5 +391,15 @@ onNext?: OnResultSubscription<Data, Variables>; | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
export declare function terminate(dataConnect: DataConnect): Promise<void>; | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<unknown, Variables>; | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<Data, Variables>; | ||
@@ -294,4 +413,10 @@ declare interface TrackedQuery<Data, Variables> { | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, authProvider?: AuthTokenProvider, transportOptions?: TransportOptions) => DataConnectTransport; | ||
/** | ||
* @internal | ||
*/ | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, appId?: string, authProvider?: AuthTokenProvider, appCheckProvider?: AppCheckTokenProvider, transportOptions?: TransportOptions, _isUsingGen?: boolean) => DataConnectTransport; | ||
/** | ||
* Options to connect to emulator | ||
*/ | ||
export declare interface TransportOptions { | ||
@@ -303,2 +428,22 @@ host: string; | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
export declare function validateArgs<Variables extends object>(connectorConfig: ConnectorConfig, dcOrVars?: DataConnect | Variables, vars?: Variables, validateVars?: boolean): ParsedArgs<Variables>; | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
export declare function validateDCOptions(dcOptions: ConnectorConfig): boolean; | ||
export { } |
@@ -28,3 +28,4 @@ import { FirebaseError } from '@firebase/util'; | ||
INVALID_ARGUMENT: 'invalid-argument', | ||
PARTIAL_ERROR: 'partial-error' | ||
PARTIAL_ERROR: 'partial-error', | ||
UNAUTHORIZED: 'unauthorized' | ||
}; | ||
@@ -126,3 +127,10 @@ /** An error returned by a DataConnect operation. */ | ||
} | ||
function dcFetch(url, body, { signal }, accessToken) { | ||
function getGoogApiClientValue(_isUsingGen) { | ||
let str = 'gl-js/ fire/' + SDK_VERSION; | ||
if (_isUsingGen) { | ||
str += ' web/gen'; | ||
} | ||
return str; | ||
} | ||
function dcFetch(url, body, { signal }, appId, accessToken, appCheckToken, _isUsingGen) { | ||
if (!connectFetch) { | ||
@@ -132,3 +140,4 @@ throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!'); | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
'Content-Type': 'application/json', | ||
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen) | ||
}; | ||
@@ -138,2 +147,8 @@ if (accessToken) { | ||
} | ||
if (appId) { | ||
headers['x-firebase-gmpid'] = appId; | ||
} | ||
if (appCheckToken) { | ||
headers['X-Firebase-AppCheck'] = appCheckToken; | ||
} | ||
const bodyStr = JSON.stringify(body); | ||
@@ -146,5 +161,6 @@ logDebug(`Making request out to ${url} with body: ${bodyStr}`); | ||
signal | ||
}).catch(err => { | ||
throw new DataConnectError(Code.OTHER, "Failed to fetch: " + JSON.stringify(err)); | ||
}) | ||
.catch(err => { | ||
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err)); | ||
}) | ||
.then(async (response) => { | ||
@@ -158,5 +174,9 @@ let jsonResponse = null; | ||
} | ||
const message = getMessage(jsonResponse); | ||
if (response.status >= 400) { | ||
logError('Error while performing request: ' + JSON.stringify(jsonResponse)); | ||
throw new DataConnectError(Code.OTHER, JSON.stringify(jsonResponse)); | ||
if (response.status === 401) { | ||
throw new DataConnectError(Code.UNAUTHORIZED, message); | ||
} | ||
throw new DataConnectError(Code.OTHER, message); | ||
} | ||
@@ -174,5 +194,11 @@ return jsonResponse; | ||
} | ||
function getMessage(obj) { | ||
if ('message' in obj) { | ||
return obj.message; | ||
} | ||
return JSON.stringify(obj); | ||
} | ||
const name = "@firebase/data-connect"; | ||
const version = "0.0.2-dataconnect-preview.877f8b7d0"; | ||
const version = "0.0.3-canary.beaa4dffb"; | ||
@@ -195,2 +221,57 @@ /** | ||
*/ | ||
/** | ||
* @internal | ||
* Abstraction around AppCheck's token fetching capabilities. | ||
*/ | ||
class AppCheckTokenProvider { | ||
constructor(appName_, appCheckProvider) { | ||
this.appName_ = appName_; | ||
this.appCheckProvider = appCheckProvider; | ||
this.appCheck = appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.getImmediate({ optional: true }); | ||
if (!this.appCheck) { | ||
void (appCheckProvider === null || appCheckProvider === void 0 ? void 0 : appCheckProvider.get().then(appCheck => (this.appCheck = appCheck)).catch()); | ||
} | ||
} | ||
getToken(forceRefresh) { | ||
if (!this.appCheck) { | ||
return new Promise((resolve, reject) => { | ||
// Support delayed initialization of FirebaseAppCheck. This allows our | ||
// customers to initialize the RTDB SDK before initializing Firebase | ||
// AppCheck and ensures that all requests are authenticated if a token | ||
// becomes available before the timoeout below expires. | ||
setTimeout(() => { | ||
if (this.appCheck) { | ||
this.getToken(forceRefresh).then(resolve, reject); | ||
} | ||
else { | ||
resolve(null); | ||
} | ||
}, 0); | ||
}); | ||
} | ||
return this.appCheck.getToken(forceRefresh); | ||
} | ||
addTokenChangeListener(listener) { | ||
var _a; | ||
void ((_a = this.appCheckProvider) === null || _a === void 0 ? void 0 : _a.get().then(appCheck => appCheck.addTokenListener(listener))); | ||
} | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
// @internal | ||
class FirebaseAuthProvider { | ||
@@ -238,3 +319,4 @@ constructor(_appName, _options, _authProvider) { | ||
.get() | ||
.then(auth => auth.removeAuthTokenListener(listener)); | ||
.then(auth => auth.removeAuthTokenListener(listener)) | ||
.catch(err => logError(err)); | ||
} | ||
@@ -479,3 +561,3 @@ } | ||
} | ||
return `${baseUrl}/v1alpha/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
return `${baseUrl}/v1beta/projects/${project}/locations/${location}/services/${service}/connectors/${connector}`; | ||
} | ||
@@ -508,6 +590,9 @@ function addToken(url, apiKey) { | ||
class RESTTransport { | ||
constructor(options, apiKey, authProvider, transportOptions) { | ||
var _a; | ||
constructor(options, apiKey, appId, authProvider, appCheckProvider, transportOptions, _isUsingGen = false) { | ||
var _a, _b; | ||
this.apiKey = apiKey; | ||
this.appId = appId; | ||
this.authProvider = authProvider; | ||
this.appCheckProvider = appCheckProvider; | ||
this._isUsingGen = _isUsingGen; | ||
this._host = ''; | ||
@@ -519,3 +604,4 @@ this._location = 'l'; | ||
this._accessToken = null; | ||
this._authInitialized = false; | ||
this._appCheckToken = null; | ||
this._lastToken = null; | ||
// TODO(mtewani): Update U to include shape of body defined in line 13. | ||
@@ -525,12 +611,11 @@ this.invokeQuery = (queryName, body) => { | ||
// TODO(mtewani): Update to proper value | ||
const withAuth = this.getWithAuth().then(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this._accessToken); | ||
}); | ||
const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), { | ||
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
operationName: queryName, | ||
variables: body | ||
}, // TODO(mtewani): This is a patch, fix this. | ||
abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen)); | ||
return { | ||
then: withAuth.then.bind(withAuth) | ||
then: withAuth.then.bind(withAuth), | ||
catch: withAuth.catch.bind(withAuth) | ||
}; | ||
@@ -540,3 +625,3 @@ }; | ||
const abortController = new AbortController(); | ||
const taskResult = this.getWithAuth().then(() => { | ||
const taskResult = this.withRetry(() => { | ||
return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), { | ||
@@ -546,3 +631,3 @@ name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`, | ||
variables: body | ||
}, abortController, this._accessToken); | ||
}, abortController, this.appId, this._accessToken, this._appCheckToken, this._isUsingGen); | ||
}); | ||
@@ -581,2 +666,7 @@ return { | ||
}); | ||
(_b = this.appCheckProvider) === null || _b === void 0 ? void 0 : _b.addTokenChangeListener(result => { | ||
const { token } = result; | ||
logDebug(`New App Check Token Available: ${token}`); | ||
this._appCheckToken = token; | ||
}); | ||
} | ||
@@ -603,22 +693,48 @@ get endpointUrl() { | ||
} | ||
getWithAuth() { | ||
async getWithAuth(forceToken = false) { | ||
var _a; | ||
let starterPromise = new Promise(resolve => resolve(this._accessToken)); | ||
if (!this._authInitialized) { | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ false) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
if (this.appCheckProvider) { | ||
this._appCheckToken = (_a = (await this.appCheckProvider.getToken())) === null || _a === void 0 ? void 0 : _a.token; | ||
} | ||
if (this.authProvider) { | ||
starterPromise = this.authProvider | ||
.getToken(/*forceToken=*/ forceToken) | ||
.then(data => { | ||
if (!data) { | ||
return null; | ||
} | ||
this._accessToken = data.accessToken; | ||
return this._accessToken; | ||
}); | ||
} | ||
else { | ||
starterPromise = new Promise(resolve => resolve('')); | ||
} | ||
return starterPromise; | ||
} | ||
_setLastToken(lastToken) { | ||
this._lastToken = lastToken; | ||
} | ||
withRetry(promiseFactory, retry = false) { | ||
let isNewToken = false; | ||
return this.getWithAuth(retry) | ||
.then(res => { | ||
isNewToken = this._lastToken !== res; | ||
this._lastToken = res; | ||
return res; | ||
}) | ||
.then(promiseFactory) | ||
.catch(err => { | ||
// Only retry if the result is unauthorized and the last token isn't the same as the new one. | ||
if ('code' in err && | ||
err.code === Code.UNAUTHORIZED && | ||
!retry && | ||
isNewToken) { | ||
logDebug('Retrying due to unauthorized'); | ||
return this.withRetry(promiseFactory, true); | ||
} | ||
throw err; | ||
}); | ||
} | ||
} | ||
@@ -642,7 +758,14 @@ | ||
*/ | ||
function mutationRef(dcInstance, queryName, variables) { | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
* @returns `MutationRef` | ||
*/ | ||
function mutationRef(dcInstance, mutationName, variables) { | ||
dcInstance.setInitialized(); | ||
const ref = { | ||
dataConnect: dcInstance, | ||
name: queryName, | ||
name: mutationName, | ||
refType: MUTATION_STR, | ||
@@ -653,2 +776,5 @@ variables: variables | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
class MutationManager { | ||
@@ -671,2 +797,7 @@ constructor(_transport) { | ||
} | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
function executeMutation(mutationRef) { | ||
@@ -706,11 +837,17 @@ return mutationRef.dataConnect._mutationManager.executeMutation(mutationRef); | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
class DataConnect { | ||
// @internal | ||
constructor(app, | ||
// TODO(mtewani): Replace with _dataConnectOptions in the future | ||
dataConnectOptions, _authProvider) { | ||
dataConnectOptions, _authProvider, _appCheckProvider) { | ||
this.app = app; | ||
this.dataConnectOptions = dataConnectOptions; | ||
this._authProvider = _authProvider; | ||
this._appCheckProvider = _appCheckProvider; | ||
this.isEmulator = false; | ||
this.initialized = false; | ||
this._initialized = false; | ||
this._isUsingGeneratedSdk = false; | ||
if (typeof process !== 'undefined' && process.env) { | ||
@@ -725,2 +862,8 @@ const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR]; | ||
} | ||
// @internal | ||
_useGeneratedSdk() { | ||
if (!this._isUsingGeneratedSdk) { | ||
this._isUsingGeneratedSdk = true; | ||
} | ||
} | ||
_delete() { | ||
@@ -730,2 +873,3 @@ _removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings())); | ||
} | ||
// @internal | ||
getSettings() { | ||
@@ -736,4 +880,5 @@ const copy = JSON.parse(JSON.stringify(this.dataConnectOptions)); | ||
} | ||
// @internal | ||
setInitialized() { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
return; | ||
@@ -748,4 +893,7 @@ } | ||
} | ||
this.initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider); | ||
if (this._appCheckProvider) { | ||
this._appCheckTokenProvider = new AppCheckTokenProvider(this.app.name, this._appCheckProvider); | ||
} | ||
this._initialized = true; | ||
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this.app.options.appId, this._authTokenProvider, this._appCheckTokenProvider, undefined, this._isUsingGeneratedSdk); | ||
if (this._transportOptions) { | ||
@@ -757,4 +905,5 @@ this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled); | ||
} | ||
// @internal | ||
enableEmulator(transportOptions) { | ||
if (this.initialized) { | ||
if (this._initialized) { | ||
logError('enableEmulator called after initialization'); | ||
@@ -767,2 +916,9 @@ throw new DataConnectError(Code.ALREADY_INITIALIZED, 'DataConnect instance already initialized!'); | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
function connectDataConnectEmulator(dc, host, port, sslEnabled = false) { | ||
@@ -782,3 +938,3 @@ dc.enableEmulator({ host, port, sslEnabled }); | ||
} | ||
if (!app) { | ||
if (!app || Object.keys(app).length === 0) { | ||
app = getApp(); | ||
@@ -797,5 +953,3 @@ } | ||
} | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
validateDCOptions(dcOptions); | ||
logDebug('Creating new DataConnect instance'); | ||
@@ -808,2 +962,25 @@ // Initialize with options. | ||
} | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
function validateDCOptions(dcOptions) { | ||
const fields = ['connector', 'location', 'service']; | ||
if (!dcOptions) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required'); | ||
} | ||
fields.forEach(field => { | ||
if (dcOptions[field] === null || dcOptions[field] === undefined) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`); | ||
} | ||
}); | ||
return true; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
function terminate(dataConnect) { | ||
@@ -835,2 +1012,3 @@ return dataConnect._delete(); | ||
const authProvider = container.getProvider('auth-internal'); | ||
const appCheckProvider = container.getProvider('app-check-internal'); | ||
let newOpts = options; | ||
@@ -840,3 +1018,6 @@ if (settings) { | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider); | ||
if (!app.options.projectId) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?'); | ||
} | ||
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider, appCheckProvider); | ||
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true)); | ||
@@ -864,5 +1045,18 @@ registerVersion(name, version, variant); | ||
*/ | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
function executeQuery(queryRef) { | ||
return queryRef.dataConnect._queryManager.executeQuery(queryRef); | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @param initialCache initial cache to use for client hydration | ||
* @returns `QueryRef` | ||
*/ | ||
function queryRef(dcInstance, queryName, variables, initialCache) { | ||
@@ -878,2 +1072,7 @@ dcInstance.setInitialized(); | ||
} | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
function toQueryRef(serializedRef) { | ||
@@ -900,2 +1099,53 @@ const { refInfo: { name, variables, connectorConfig } } = serializedRef; | ||
*/ | ||
/** | ||
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable, | ||
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in. | ||
* @param connectorConfig | ||
* @param dcOrVars | ||
* @param vars | ||
* @param validateVars | ||
* @returns {DataConnect} and {Variables} instance | ||
* @internal | ||
*/ | ||
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) { | ||
let dcInstance; | ||
let realVars; | ||
if (dcOrVars && 'enableEmulator' in dcOrVars) { | ||
dcInstance = dcOrVars; | ||
realVars = vars; | ||
} | ||
else { | ||
dcInstance = getDataConnect(connectorConfig); | ||
realVars = dcOrVars; | ||
} | ||
if (!dcInstance || (!realVars && validateVars)) { | ||
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.'); | ||
} | ||
return { dc: dcInstance, vars: realVars }; | ||
} | ||
/** | ||
* @license | ||
* Copyright 2024 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observerOrOnNext observer object or next function. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
function subscribe(queryRefOrSerializedResult, observerOrOnNext, onError, onComplete) { | ||
@@ -951,3 +1201,3 @@ let ref; | ||
export { DataConnect, FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR, FirebaseAuthProvider, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef }; | ||
export { DataConnect, MUTATION_STR, MutationManager, QUERY_STR, SOURCE_CACHE, SOURCE_SERVER, connectDataConnectEmulator, executeMutation, executeQuery, getDataConnect, mutationRef, parseOptions, queryRef, setLogLevel, subscribe, terminate, toQueryRef, validateArgs, validateDCOptions }; | ||
//# sourceMappingURL=index.node.esm.js.map |
@@ -20,11 +20,16 @@ /** | ||
/** | ||
* | ||
* @public | ||
* @param queryRef | ||
* @param onResult | ||
* @param onErr | ||
* @param initialCache | ||
* @returns | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observer observer object to use for subscribing. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, observer: SubscriptionOptions<Data, Variables>): QueryUnsubscribe; | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param onNext Callback to call when result comes back. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, onNext: OnResultSubscription<Data, Variables>, onError?: OnErrorSubscription, onComplete?: OnCompleteSubscription): QueryUnsubscribe; |
@@ -18,2 +18,3 @@ /** | ||
import { FirebaseApp } from '@firebase/app'; | ||
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; | ||
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; | ||
@@ -23,2 +24,5 @@ import { Provider } from '@firebase/component'; | ||
import { MutationManager } from './Mutation'; | ||
/** | ||
* Connector Config for calling Data Connect backend. | ||
*/ | ||
export interface ConnectorConfig { | ||
@@ -29,2 +33,5 @@ location: string; | ||
} | ||
/** | ||
* Options to connect to emulator | ||
*/ | ||
export interface TransportOptions { | ||
@@ -35,3 +42,2 @@ host: string; | ||
} | ||
export declare const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = "FIREBASE_DATA_CONNECT_EMULATOR_HOST"; | ||
/** | ||
@@ -44,5 +50,11 @@ * | ||
export declare function parseOptions(fullHost: string): TransportOptions; | ||
/** | ||
* DataConnectOptions including project id | ||
*/ | ||
export interface DataConnectOptions extends ConnectorConfig { | ||
projectId: string; | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
export declare class DataConnect { | ||
@@ -52,6 +64,7 @@ readonly app: FirebaseApp; | ||
private readonly _authProvider; | ||
private readonly _appCheckProvider; | ||
_queryManager: QueryManager; | ||
_mutationManager: MutationManager; | ||
isEmulator: boolean; | ||
initialized: boolean; | ||
_initialized: boolean; | ||
private _transport; | ||
@@ -61,3 +74,6 @@ private _transportClass; | ||
private _authTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
_isUsingGeneratedSdk: boolean; | ||
private _appCheckTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>, _appCheckProvider: Provider<AppCheckInternalComponentName>); | ||
_useGeneratedSdk(): void; | ||
_delete(): Promise<void>; | ||
@@ -68,5 +84,33 @@ getSettings(): ConnectorConfig; | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
export declare function connectDataConnectEmulator(dc: DataConnect, host: string, port?: number, sslEnabled?: boolean): void; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(options: ConnectorConfig): DataConnect; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param app FirebaseApp to initialize to. | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(app: FirebaseApp, options: ConnectorConfig): DataConnect; | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
export declare function validateDCOptions(dcOptions: ConnectorConfig): boolean; | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
export declare function terminate(dataConnect: DataConnect): Promise<void>; |
@@ -23,1 +23,2 @@ /** | ||
export { setLogLevel } from '../logger'; | ||
export { validateArgs } from '../util/validateArgs'; |
@@ -23,4 +23,18 @@ /** | ||
} | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, queryName: string): MutationRef<Data, undefined>; | ||
/** | ||
* Creates a `MutationRef` | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
*/ | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, mutationName: string): MutationRef<Data, undefined>; | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
*/ | ||
export declare function mutationRef<Data, Variables>(dcInstance: DataConnect, mutationName: string, variables: Variables): MutationRef<Data, Variables>; | ||
/** | ||
* @internal | ||
*/ | ||
export declare class MutationManager { | ||
@@ -32,7 +46,18 @@ private _transport; | ||
} | ||
/** | ||
* Mutation Result from `executeMutation` | ||
*/ | ||
export interface MutationResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
ref: MutationRef<Data, Variables>; | ||
} | ||
/** | ||
* Mutation return value from `executeMutation` | ||
*/ | ||
export interface MutationPromise<Data, Variables> extends PromiseLike<MutationResult<Data, Variables>> { | ||
} | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
export declare function executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; |
@@ -20,5 +20,17 @@ /** | ||
import { OperationRef, QUERY_STR, DataConnectResult, SerializedRef } from './Reference'; | ||
/** | ||
* Signature for `OnResultSubscription` for `subscribe` | ||
*/ | ||
export declare type OnResultSubscription<Data, Variables> = (res: QueryResult<Data, Variables>) => void; | ||
/** | ||
* Signature for `OnErrorSubscription` for `subscribe` | ||
*/ | ||
export declare type OnErrorSubscription = (err?: DataConnectError) => void; | ||
/** | ||
* Signature for unsubscribe from `subscribe` | ||
*/ | ||
export declare type QueryUnsubscribe = () => void; | ||
/** | ||
* Representation of user provided subscription options. | ||
*/ | ||
export interface DataConnectSubscription<Data, Variables> { | ||
@@ -29,5 +41,11 @@ userCallback: OnResultSubscription<Data, Variables>; | ||
} | ||
/** | ||
* QueryRef object | ||
*/ | ||
export interface QueryRef<Data, Variables> extends OperationRef<Data, Variables> { | ||
refType: typeof QUERY_STR; | ||
} | ||
/** | ||
* Result of `executeQuery` | ||
*/ | ||
export interface QueryResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -37,9 +55,41 @@ ref: QueryRef<Data, Variables>; | ||
} | ||
/** | ||
* Promise returned from `executeQuery` | ||
*/ | ||
export interface QueryPromise<Data, Variables> extends PromiseLike<QueryResult<Data, Variables>> { | ||
} | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
export declare function executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data>(dcInstance: DataConnect, queryName: string): QueryRef<Data, undefined>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data, Variables>(dcInstance: DataConnect, queryName: string, variables: Variables): QueryRef<Data, Variables>; | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<unknown, Variables>; | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<Data, Variables>; | ||
/** | ||
* `OnCompleteSubscription` | ||
*/ | ||
export declare type OnCompleteSubscription = () => void; | ||
/** | ||
* Representation of full observer options in `subscribe` | ||
*/ | ||
export interface SubscriptionOptions<Data, Variables> { | ||
@@ -46,0 +96,0 @@ onNext?: OnResultSubscription<Data, Variables>; |
@@ -38,2 +38,5 @@ /** | ||
} | ||
/** | ||
* Serialized RefInfo as a result of `QueryResult.toJSON().refInfo` | ||
*/ | ||
export interface RefInfo<Variables> { | ||
@@ -44,4 +47,7 @@ name: string; | ||
} | ||
/** | ||
* Serialized Ref as a result of `QueryResult.toJSON()` | ||
*/ | ||
export interface SerializedRef<Data, Variables> extends OpResult<Data> { | ||
refInfo: RefInfo<Variables>; | ||
} |
@@ -18,3 +18,3 @@ /** | ||
import { FirebaseError } from '@firebase/util'; | ||
export declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error'; | ||
export declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error' | 'unauthorized'; | ||
export declare type Code = DataConnectErrorCode; | ||
@@ -28,2 +28,3 @@ export declare const Code: { | ||
PARTIAL_ERROR: DataConnectErrorCode; | ||
UNAUTHORIZED: DataConnectErrorCode; | ||
}; | ||
@@ -30,0 +31,0 @@ /** An error returned by a DataConnect operation. */ |
@@ -17,3 +17,3 @@ /** | ||
*/ | ||
import { FirebaseOptions } from '@firebase/app'; | ||
import { FirebaseOptions } from '@firebase/app-types'; | ||
import { FirebaseAuthInternalName, FirebaseAuthTokenData } from '@firebase/auth-interop-types'; | ||
@@ -20,0 +20,0 @@ import { Provider } from '@firebase/component'; |
@@ -31,3 +31,3 @@ /** | ||
constructor(transport: DataConnectTransport); | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<unknown, unknown>; | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<Data, Variables>; | ||
addSubscription<Data, Variables>(queryRef: OperationRef<Data, Variables>, onResultCallback: OnResultSubscription<Data, Variables>, onErrorCallback?: OnErrorSubscription, initialCache?: OpResult<Data>): () => void; | ||
@@ -34,0 +34,0 @@ executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; |
@@ -18,5 +18,5 @@ /** | ||
export declare function initializeFetch(fetchImpl: typeof fetch): void; | ||
export declare function dcFetch<T, U>(url: string, body: U, { signal }: AbortController, accessToken: string | null): Promise<{ | ||
export declare function dcFetch<T, U>(url: string, body: U, { signal }: AbortController, appId: string | null, accessToken: string | null, appCheckToken: string | null, _isUsingGen: boolean): Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; |
@@ -18,3 +18,7 @@ /** | ||
import { DataConnectOptions, TransportOptions } from '../../api/DataConnect'; | ||
import { AppCheckTokenProvider } from '../../core/AppCheckTokenProvider'; | ||
import { AuthTokenProvider } from '../../core/FirebaseAuthProvider'; | ||
/** | ||
* @internal | ||
*/ | ||
export interface DataConnectTransport { | ||
@@ -37,11 +41,5 @@ invokeQuery<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
} | ||
export interface QueryResponse<T> extends CancellableOperation<T> { | ||
} | ||
export interface MutationResponse<T> extends CancellableOperation<T> { | ||
} | ||
export interface Sender<T> { | ||
abort: () => void; | ||
send: () => Promise<T>; | ||
} | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, authProvider?: AuthTokenProvider, transportOptions?: TransportOptions) => DataConnectTransport; | ||
export * from '../../core/FirebaseAuthProvider'; | ||
/** | ||
* @internal | ||
*/ | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, appId?: string, authProvider?: AuthTokenProvider, appCheckProvider?: AppCheckTokenProvider, transportOptions?: TransportOptions, _isUsingGen?: boolean) => DataConnectTransport; |
@@ -18,2 +18,3 @@ /** | ||
import { DataConnectOptions, TransportOptions } from '../../api/DataConnect'; | ||
import { AppCheckTokenProvider } from '../../core/AppCheckTokenProvider'; | ||
import { AuthTokenProvider } from '../../core/FirebaseAuthProvider'; | ||
@@ -23,3 +24,6 @@ import { DataConnectTransport } from '.'; | ||
private apiKey?; | ||
private appId?; | ||
private authProvider?; | ||
private appCheckProvider?; | ||
private _isUsingGen; | ||
private _host; | ||
@@ -33,15 +37,25 @@ private _port; | ||
private _accessToken; | ||
private _authInitialized; | ||
constructor(options: DataConnectOptions, apiKey?: string | undefined, authProvider?: AuthTokenProvider | undefined, transportOptions?: TransportOptions | undefined); | ||
private _appCheckToken; | ||
private _lastToken; | ||
constructor(options: DataConnectOptions, apiKey?: string | undefined, appId?: string, authProvider?: AuthTokenProvider | undefined, appCheckProvider?: AppCheckTokenProvider | undefined, transportOptions?: TransportOptions | undefined, _isUsingGen?: boolean); | ||
get endpointUrl(): string; | ||
useEmulator(host: string, port?: number, isSecure?: boolean): void; | ||
onTokenChanged(newToken: string | null): void; | ||
getWithAuth(): Promise<string>; | ||
invokeQuery: <T, U = unknown>(queryName: string, body: U) => { | ||
then: any; | ||
}; | ||
invokeMutation: <T, U = unknown>(mutationName: string, body: U) => { | ||
then: any; | ||
cancel: () => void; | ||
}; | ||
getWithAuth(forceToken?: boolean): Promise<string>; | ||
_setLastToken(lastToken: string | null): void; | ||
withRetry<T>(promiseFactory: () => Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>, retry?: boolean): Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeQuery: <T, U>(queryName: string, body?: U) => PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeMutation: <T, U>(queryName: string, body?: U) => PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
} |
@@ -7,2 +7,5 @@ /** | ||
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; | ||
import { AppCheckTokenListener } from '@firebase/app-check-interop-types'; | ||
import { AppCheckTokenResult } from '@firebase/app-check-interop-types'; | ||
import { FirebaseApp } from '@firebase/app'; | ||
@@ -12,9 +15,10 @@ import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; | ||
import { FirebaseError } from '@firebase/util'; | ||
import { FirebaseOptions } from '@firebase/app'; | ||
import { LogLevelString } from '@firebase/logger'; | ||
import { Provider } from '@firebase/component'; | ||
export declare type AuthTokenListener = (token: string | null) => void; | ||
/* Excluded from this release type: AppCheckTokenProvider */ | ||
export declare interface AuthTokenProvider { | ||
declare type AuthTokenListener = (token: string | null) => void; | ||
declare interface AuthTokenProvider { | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
@@ -30,4 +34,14 @@ addTokenChangeListener(listener: AuthTokenListener): void; | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
export declare function connectDataConnectEmulator(dc: DataConnect, host: string, port?: number, sslEnabled?: boolean): void; | ||
/** | ||
* Connector Config for calling Data Connect backend. | ||
*/ | ||
export declare interface ConnectorConfig { | ||
@@ -39,2 +53,5 @@ location: string; | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
export declare class DataConnect { | ||
@@ -44,6 +61,7 @@ readonly app: FirebaseApp; | ||
private readonly _authProvider; | ||
private readonly _appCheckProvider; | ||
_queryManager: QueryManager; | ||
_mutationManager: MutationManager; | ||
isEmulator: boolean; | ||
initialized: boolean; | ||
_initialized: boolean; | ||
private _transport; | ||
@@ -53,3 +71,6 @@ private _transportClass; | ||
private _authTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
_isUsingGeneratedSdk: boolean; | ||
private _appCheckTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>, _appCheckProvider: Provider<AppCheckInternalComponentName>); | ||
_useGeneratedSdk(): void; | ||
_delete(): Promise<void>; | ||
@@ -85,4 +106,7 @@ getSettings(): ConnectorConfig; | ||
declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error'; | ||
declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error' | 'unauthorized'; | ||
/** | ||
* DataConnectOptions including project id | ||
*/ | ||
export declare interface DataConnectOptions extends ConnectorConfig { | ||
@@ -96,2 +120,5 @@ projectId: string; | ||
/** | ||
* Representation of user provided subscription options. | ||
*/ | ||
export declare interface DataConnectSubscription<Data, Variables> { | ||
@@ -103,36 +130,31 @@ userCallback: OnResultSubscription<Data, Variables>; | ||
export declare interface DataConnectTransport { | ||
invokeQuery<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeMutation<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
useEmulator(host: string, port?: number, sslEnabled?: boolean): void; | ||
onTokenChanged: (token: string | null) => void; | ||
} | ||
/* Excluded from this release type: DataConnectTransport */ | ||
export declare type DataSource = typeof SOURCE_CACHE | typeof SOURCE_SERVER; | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
export declare function executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
export declare function executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
export declare const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = "FIREBASE_DATA_CONNECT_EMULATOR_HOST"; | ||
export declare class FirebaseAuthProvider implements AuthTokenProvider { | ||
private _appName; | ||
private _options; | ||
private _authProvider; | ||
private _auth; | ||
constructor(_appName: string, _options: FirebaseOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
addTokenChangeListener(listener: AuthTokenListener): void; | ||
removeTokenChangeListener(listener: (token: string | null) => void): void; | ||
} | ||
/** | ||
* Initialize DataConnect instance | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(options: ConnectorConfig): DataConnect; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param app FirebaseApp to initialize to. | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(app: FirebaseApp, options: ConnectorConfig): DataConnect; | ||
@@ -142,9 +164,7 @@ | ||
export declare class MutationManager { | ||
private _transport; | ||
private _inflight; | ||
constructor(_transport: DataConnectTransport); | ||
executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; | ||
} | ||
/* Excluded from this release type: MutationManager */ | ||
/** | ||
* Mutation return value from `executeMutation` | ||
*/ | ||
export declare interface MutationPromise<Data, Variables> extends PromiseLike<MutationResult<Data, Variables>> { | ||
@@ -157,9 +177,20 @@ } | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, queryName: string): MutationRef<Data, undefined>; | ||
/** | ||
* Creates a `MutationRef` | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
*/ | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, mutationName: string): MutationRef<Data, undefined>; | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
*/ | ||
export declare function mutationRef<Data, Variables>(dcInstance: DataConnect, mutationName: string, variables: Variables): MutationRef<Data, Variables>; | ||
export declare interface MutationResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Mutation Result from `executeMutation` | ||
*/ | ||
export declare interface MutationResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -169,6 +200,15 @@ ref: MutationRef<Data, Variables>; | ||
/** | ||
* `OnCompleteSubscription` | ||
*/ | ||
export declare type OnCompleteSubscription = () => void; | ||
/** | ||
* Signature for `OnErrorSubscription` for `subscribe` | ||
*/ | ||
export declare type OnErrorSubscription = (err?: DataConnectError) => void; | ||
/** | ||
* Signature for `OnResultSubscription` for `subscribe` | ||
*/ | ||
export declare type OnResultSubscription<Data, Variables> = (res: QueryResult<Data, Variables>) => void; | ||
@@ -189,2 +229,7 @@ | ||
declare interface ParsedArgs<Variables> { | ||
dc: DataConnect; | ||
vars: Variables; | ||
} | ||
/* Excluded from this release type: parseOptions */ | ||
@@ -198,3 +243,3 @@ | ||
constructor(transport: DataConnectTransport); | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<unknown, unknown>; | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<Data, Variables>; | ||
addSubscription<Data, Variables>(queryRef: OperationRef<Data, Variables>, onResultCallback: OnResultSubscription<Data, Variables>, onErrorCallback?: OnErrorSubscription, initialCache?: OpResult<Data>): () => void; | ||
@@ -205,5 +250,11 @@ executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
/** | ||
* Promise returned from `executeQuery` | ||
*/ | ||
export declare interface QueryPromise<Data, Variables> extends PromiseLike<QueryResult<Data, Variables>> { | ||
} | ||
/** | ||
* QueryRef object | ||
*/ | ||
export declare interface QueryRef<Data, Variables> extends OperationRef<Data, Variables> { | ||
@@ -213,9 +264,22 @@ refType: typeof QUERY_STR; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data>(dcInstance: DataConnect, queryName: string): QueryRef<Data, undefined>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data, Variables>(dcInstance: DataConnect, queryName: string, variables: Variables): QueryRef<Data, Variables>; | ||
export declare interface QueryResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Result of `executeQuery` | ||
*/ | ||
export declare interface QueryResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -226,2 +290,5 @@ ref: QueryRef<Data, Variables>; | ||
/** | ||
* Signature for unsubscribe from `subscribe` | ||
*/ | ||
export declare type QueryUnsubscribe = () => void; | ||
@@ -231,2 +298,5 @@ | ||
/** | ||
* Serialized RefInfo as a result of `QueryResult.toJSON().refInfo` | ||
*/ | ||
export declare interface RefInfo<Variables> { | ||
@@ -238,7 +308,5 @@ name: string; | ||
export declare interface Sender<T> { | ||
abort: () => void; | ||
send: () => Promise<T>; | ||
} | ||
/** | ||
* Serialized Ref as a result of `QueryResult.toJSON()` | ||
*/ | ||
export declare interface SerializedRef<Data, Variables> extends OpResult<Data> { | ||
@@ -255,14 +323,22 @@ refInfo: RefInfo<Variables>; | ||
/** | ||
* | ||
* @public | ||
* @param queryRef | ||
* @param onResult | ||
* @param onErr | ||
* @param initialCache | ||
* @returns | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observer observer object to use for subscribing. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, observer: SubscriptionOptions<Data, Variables>): QueryUnsubscribe; | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param onNext Callback to call when result comes back. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, onNext: OnResultSubscription<Data, Variables>, onError?: OnErrorSubscription, onComplete?: OnCompleteSubscription): QueryUnsubscribe; | ||
/** | ||
* Representation of full observer options in `subscribe` | ||
*/ | ||
export declare interface SubscriptionOptions<Data, Variables> { | ||
@@ -274,5 +350,15 @@ onNext?: OnResultSubscription<Data, Variables>; | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
export declare function terminate(dataConnect: DataConnect): Promise<void>; | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<unknown, Variables>; | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<Data, Variables>; | ||
@@ -286,4 +372,7 @@ declare interface TrackedQuery<Data, Variables> { | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, authProvider?: AuthTokenProvider, transportOptions?: TransportOptions) => DataConnectTransport; | ||
/* Excluded from this release type: TransportClass */ | ||
/** | ||
* Options to connect to emulator | ||
*/ | ||
export declare interface TransportOptions { | ||
@@ -295,2 +384,6 @@ host: string; | ||
/* Excluded from this release type: validateArgs */ | ||
/* Excluded from this release type: validateDCOptions */ | ||
export { } |
@@ -7,5 +7,4 @@ /** | ||
import { FirebaseApp } from '@firebase/app'; | ||
import { FirebaseOptions } from '@firebase/app'; | ||
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; | ||
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; | ||
import { FirebaseAuthTokenData } from '@firebase/auth-interop-types'; | ||
import { Provider } from '@firebase/component'; | ||
@@ -15,7 +14,3 @@ import { LogLevelString } from '@firebase/logger'; | ||
export declare type AuthTokenListener = (token: string | null) => void; | ||
export declare interface AuthTokenProvider { | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
addTokenChangeListener(listener: AuthTokenListener): void; | ||
} | ||
export declare interface CancellableOperation<T> extends PromiseLike<{ | ||
@@ -26,3 +21,13 @@ data: T; | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
export declare function connectDataConnectEmulator(dc: DataConnect, host: string, port?: number, sslEnabled?: boolean): void; | ||
/** | ||
* Connector Config for calling Data Connect backend. | ||
*/ | ||
export declare interface ConnectorConfig { | ||
@@ -33,2 +38,5 @@ location: string; | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
export declare class DataConnect { | ||
@@ -38,4 +46,3 @@ readonly app: FirebaseApp; | ||
isEmulator: boolean; | ||
initialized: boolean; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>, _appCheckProvider: Provider<AppCheckInternalComponentName>); | ||
getSettings(): ConnectorConfig; | ||
@@ -45,2 +52,5 @@ setInitialized(): void; | ||
} | ||
/** | ||
* DataConnectOptions including project id | ||
*/ | ||
export declare interface DataConnectOptions extends ConnectorConfig { | ||
@@ -52,2 +62,5 @@ projectId: string; | ||
} | ||
/** | ||
* Representation of user provided subscription options. | ||
*/ | ||
export declare interface DataConnectSubscription<Data, Variables> { | ||
@@ -58,31 +71,32 @@ userCallback: OnResultSubscription<Data, Variables>; | ||
} | ||
export declare interface DataConnectTransport { | ||
invokeQuery<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeMutation<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
useEmulator(host: string, port?: number, sslEnabled?: boolean): void; | ||
onTokenChanged: (token: string | null) => void; | ||
} | ||
/* Excluded from this release type: DataConnectTransport */ | ||
export declare type DataSource = typeof SOURCE_CACHE | typeof SOURCE_SERVER; | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
export declare function executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
export declare function executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
export declare const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = "FIREBASE_DATA_CONNECT_EMULATOR_HOST"; | ||
export declare class FirebaseAuthProvider implements AuthTokenProvider { | ||
constructor(_appName: string, _options: FirebaseOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
getToken(forceRefresh: boolean): Promise<FirebaseAuthTokenData | null>; | ||
addTokenChangeListener(listener: AuthTokenListener): void; | ||
removeTokenChangeListener(listener: (token: string | null) => void): void; | ||
} | ||
/** | ||
* Initialize DataConnect instance | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(options: ConnectorConfig): DataConnect; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param app FirebaseApp to initialize to. | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(app: FirebaseApp, options: ConnectorConfig): DataConnect; | ||
export declare const MUTATION_STR = "mutation"; | ||
export declare class MutationManager { | ||
constructor(_transport: DataConnectTransport); | ||
executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; | ||
} | ||
/* Excluded from this release type: MutationManager */ | ||
/** | ||
* Mutation return value from `executeMutation` | ||
*/ | ||
export declare interface MutationPromise<Data, Variables> extends PromiseLike<MutationResult<Data, Variables>> { | ||
@@ -93,11 +107,32 @@ } | ||
} | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, queryName: string): MutationRef<Data, undefined>; | ||
/** | ||
* Creates a `MutationRef` | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
*/ | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, mutationName: string): MutationRef<Data, undefined>; | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
*/ | ||
export declare function mutationRef<Data, Variables>(dcInstance: DataConnect, mutationName: string, variables: Variables): MutationRef<Data, Variables>; | ||
export declare interface MutationResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Mutation Result from `executeMutation` | ||
*/ | ||
export declare interface MutationResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
ref: MutationRef<Data, Variables>; | ||
} | ||
/** | ||
* `OnCompleteSubscription` | ||
*/ | ||
export declare type OnCompleteSubscription = () => void; | ||
/** | ||
* Signature for `OnErrorSubscription` for `subscribe` | ||
*/ | ||
export declare type OnErrorSubscription = (err?: FirebaseError) => void; | ||
/** | ||
* Signature for `OnResultSubscription` for `subscribe` | ||
*/ | ||
export declare type OnResultSubscription<Data, Variables> = (res: QueryResult<Data, Variables>) => void; | ||
@@ -117,11 +152,31 @@ export declare interface OperationRef<_Data, Variables> { | ||
export declare const QUERY_STR = "query"; | ||
/** | ||
* Promise returned from `executeQuery` | ||
*/ | ||
export declare interface QueryPromise<Data, Variables> extends PromiseLike<QueryResult<Data, Variables>> { | ||
} | ||
/** | ||
* QueryRef object | ||
*/ | ||
export declare interface QueryRef<Data, Variables> extends OperationRef<Data, Variables> { | ||
refType: typeof QUERY_STR; | ||
} | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data>(dcInstance: DataConnect, queryName: string): QueryRef<Data, undefined>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data, Variables>(dcInstance: DataConnect, queryName: string, variables: Variables): QueryRef<Data, Variables>; | ||
export declare interface QueryResponse<T> extends CancellableOperation<T> { | ||
} | ||
/** | ||
* Result of `executeQuery` | ||
*/ | ||
export declare interface QueryResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -131,4 +186,10 @@ ref: QueryRef<Data, Variables>; | ||
} | ||
/** | ||
* Signature for unsubscribe from `subscribe` | ||
*/ | ||
export declare type QueryUnsubscribe = () => void; | ||
export declare type ReferenceType = typeof QUERY_STR | typeof MUTATION_STR; | ||
/** | ||
* Serialized RefInfo as a result of `QueryResult.toJSON().refInfo` | ||
*/ | ||
export declare interface RefInfo<Variables> { | ||
@@ -139,6 +200,5 @@ name: string; | ||
} | ||
export declare interface Sender<T> { | ||
abort: () => void; | ||
send: () => Promise<T>; | ||
} | ||
/** | ||
* Serialized Ref as a result of `QueryResult.toJSON()` | ||
*/ | ||
export declare interface SerializedRef<Data, Variables> extends OpResult<Data> { | ||
@@ -151,12 +211,20 @@ refInfo: RefInfo<Variables>; | ||
/** | ||
* | ||
* @public | ||
* @param queryRef | ||
* @param onResult | ||
* @param onErr | ||
* @param initialCache | ||
* @returns | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observer observer object to use for subscribing. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, observer: SubscriptionOptions<Data, Variables>): QueryUnsubscribe; | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param onNext Callback to call when result comes back. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, onNext: OnResultSubscription<Data, Variables>, onError?: OnErrorSubscription, onComplete?: OnCompleteSubscription): QueryUnsubscribe; | ||
/** | ||
* Representation of full observer options in `subscribe` | ||
*/ | ||
export declare interface SubscriptionOptions<Data, Variables> { | ||
@@ -167,5 +235,18 @@ onNext?: OnResultSubscription<Data, Variables>; | ||
} | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
export declare function terminate(dataConnect: DataConnect): Promise<void>; | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<unknown, Variables>; | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, authProvider?: AuthTokenProvider, transportOptions?: TransportOptions) => DataConnectTransport; | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<Data, Variables>; | ||
/* Excluded from this release type: TransportClass */ | ||
/** | ||
* Options to connect to emulator | ||
*/ | ||
export declare interface TransportOptions { | ||
@@ -176,2 +257,4 @@ host: string; | ||
} | ||
/* Excluded from this release type: validateArgs */ | ||
/* Excluded from this release type: validateDCOptions */ | ||
export {}; |
@@ -20,11 +20,16 @@ /** | ||
/** | ||
* | ||
* @public | ||
* @param queryRef | ||
* @param onResult | ||
* @param onErr | ||
* @param initialCache | ||
* @returns | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param observer observer object to use for subscribing. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, observer: SubscriptionOptions<Data, Variables>): QueryUnsubscribe; | ||
/** | ||
* Subscribe to a `QueryRef` | ||
* @param queryRefOrSerializedResult query ref or serialized result. | ||
* @param onNext Callback to call when result comes back. | ||
* @param onError Callback to call when error gets thrown. | ||
* @param onComplete Called when subscription completes. | ||
* @returns `SubscriptionOptions` | ||
*/ | ||
export declare function subscribe<Data, Variables>(queryRefOrSerializedResult: QueryRef<Data, Variables> | SerializedRef<Data, Variables>, onNext: OnResultSubscription<Data, Variables>, onError?: OnErrorSubscription, onComplete?: OnCompleteSubscription): QueryUnsubscribe; |
@@ -18,2 +18,3 @@ /** | ||
import { FirebaseApp } from '@firebase/app'; | ||
import { AppCheckInternalComponentName } from '@firebase/app-check-interop-types'; | ||
import { FirebaseAuthInternalName } from '@firebase/auth-interop-types'; | ||
@@ -23,2 +24,5 @@ import { Provider } from '@firebase/component'; | ||
import { MutationManager } from './Mutation'; | ||
/** | ||
* Connector Config for calling Data Connect backend. | ||
*/ | ||
export interface ConnectorConfig { | ||
@@ -29,2 +33,5 @@ location: string; | ||
} | ||
/** | ||
* Options to connect to emulator | ||
*/ | ||
export interface TransportOptions { | ||
@@ -35,3 +42,2 @@ host: string; | ||
} | ||
export declare const FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR = "FIREBASE_DATA_CONNECT_EMULATOR_HOST"; | ||
/** | ||
@@ -44,5 +50,11 @@ * | ||
export declare function parseOptions(fullHost: string): TransportOptions; | ||
/** | ||
* DataConnectOptions including project id | ||
*/ | ||
export interface DataConnectOptions extends ConnectorConfig { | ||
projectId: string; | ||
} | ||
/** | ||
* Class representing Firebase Data Connect | ||
*/ | ||
export declare class DataConnect { | ||
@@ -52,6 +64,7 @@ readonly app: FirebaseApp; | ||
private readonly _authProvider; | ||
private readonly _appCheckProvider; | ||
_queryManager: QueryManager; | ||
_mutationManager: MutationManager; | ||
isEmulator: boolean; | ||
initialized: boolean; | ||
_initialized: boolean; | ||
private _transport; | ||
@@ -61,3 +74,6 @@ private _transportClass; | ||
private _authTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>); | ||
_isUsingGeneratedSdk: boolean; | ||
private _appCheckTokenProvider?; | ||
constructor(app: FirebaseApp, dataConnectOptions: DataConnectOptions, _authProvider: Provider<FirebaseAuthInternalName>, _appCheckProvider: Provider<AppCheckInternalComponentName>); | ||
_useGeneratedSdk(): void; | ||
_delete(): Promise<void>; | ||
@@ -68,5 +84,33 @@ getSettings(): ConnectorConfig; | ||
} | ||
/** | ||
* Connect to the DataConnect Emulator | ||
* @param dc Data Connect instance | ||
* @param host host of emulator server | ||
* @param port port of emulator server | ||
* @param sslEnabled use https | ||
*/ | ||
export declare function connectDataConnectEmulator(dc: DataConnect, host: string, port?: number, sslEnabled?: boolean): void; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(options: ConnectorConfig): DataConnect; | ||
/** | ||
* Initialize DataConnect instance | ||
* @param app FirebaseApp to initialize to. | ||
* @param options ConnectorConfig | ||
*/ | ||
export declare function getDataConnect(app: FirebaseApp, options: ConnectorConfig): DataConnect; | ||
/** | ||
* | ||
* @param dcOptions | ||
* @returns {void} | ||
* @internal | ||
*/ | ||
export declare function validateDCOptions(dcOptions: ConnectorConfig): boolean; | ||
/** | ||
* Delete DataConnect instance | ||
* @param dataConnect DataConnect instance | ||
* @returns | ||
*/ | ||
export declare function terminate(dataConnect: DataConnect): Promise<void>; |
@@ -23,1 +23,2 @@ /** | ||
export { setLogLevel } from '../logger'; | ||
export { validateArgs } from '../util/validateArgs'; |
@@ -23,4 +23,18 @@ /** | ||
} | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, queryName: string): MutationRef<Data, undefined>; | ||
/** | ||
* Creates a `MutationRef` | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
*/ | ||
export declare function mutationRef<Data>(dcInstance: DataConnect, mutationName: string): MutationRef<Data, undefined>; | ||
/** | ||
* | ||
* @param dcInstance Data Connect instance | ||
* @param mutationName name of mutation | ||
* @param variables variables to send with mutation | ||
*/ | ||
export declare function mutationRef<Data, Variables>(dcInstance: DataConnect, mutationName: string, variables: Variables): MutationRef<Data, Variables>; | ||
/** | ||
* @internal | ||
*/ | ||
export declare class MutationManager { | ||
@@ -32,7 +46,18 @@ private _transport; | ||
} | ||
/** | ||
* Mutation Result from `executeMutation` | ||
*/ | ||
export interface MutationResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
ref: MutationRef<Data, Variables>; | ||
} | ||
/** | ||
* Mutation return value from `executeMutation` | ||
*/ | ||
export interface MutationPromise<Data, Variables> extends PromiseLike<MutationResult<Data, Variables>> { | ||
} | ||
/** | ||
* Execute Mutation | ||
* @param mutationRef mutation to execute | ||
* @returns `MutationRef` | ||
*/ | ||
export declare function executeMutation<Data, Variables>(mutationRef: MutationRef<Data, Variables>): MutationPromise<Data, Variables>; |
@@ -20,5 +20,17 @@ /** | ||
import { OperationRef, QUERY_STR, DataConnectResult, SerializedRef } from './Reference'; | ||
/** | ||
* Signature for `OnResultSubscription` for `subscribe` | ||
*/ | ||
export declare type OnResultSubscription<Data, Variables> = (res: QueryResult<Data, Variables>) => void; | ||
/** | ||
* Signature for `OnErrorSubscription` for `subscribe` | ||
*/ | ||
export declare type OnErrorSubscription = (err?: DataConnectError) => void; | ||
/** | ||
* Signature for unsubscribe from `subscribe` | ||
*/ | ||
export declare type QueryUnsubscribe = () => void; | ||
/** | ||
* Representation of user provided subscription options. | ||
*/ | ||
export interface DataConnectSubscription<Data, Variables> { | ||
@@ -29,5 +41,11 @@ userCallback: OnResultSubscription<Data, Variables>; | ||
} | ||
/** | ||
* QueryRef object | ||
*/ | ||
export interface QueryRef<Data, Variables> extends OperationRef<Data, Variables> { | ||
refType: typeof QUERY_STR; | ||
} | ||
/** | ||
* Result of `executeQuery` | ||
*/ | ||
export interface QueryResult<Data, Variables> extends DataConnectResult<Data, Variables> { | ||
@@ -37,9 +55,41 @@ ref: QueryRef<Data, Variables>; | ||
} | ||
/** | ||
* Promise returned from `executeQuery` | ||
*/ | ||
export interface QueryPromise<Data, Variables> extends PromiseLike<QueryResult<Data, Variables>> { | ||
} | ||
/** | ||
* Execute Query | ||
* @param queryRef query to execute. | ||
* @returns `QueryPromise` | ||
*/ | ||
export declare function executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data>(dcInstance: DataConnect, queryName: string): QueryRef<Data, undefined>; | ||
/** | ||
* Execute Query | ||
* @param dcInstance Data Connect instance to use. | ||
* @param queryName Query to execute | ||
* @param variables Variables to execute with | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function queryRef<Data, Variables>(dcInstance: DataConnect, queryName: string, variables: Variables): QueryRef<Data, Variables>; | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<unknown, Variables>; | ||
/** | ||
* Converts serialized ref to query ref | ||
* @param serializedRef ref to convert to `QueryRef` | ||
* @returns `QueryRef` | ||
*/ | ||
export declare function toQueryRef<Data, Variables>(serializedRef: SerializedRef<Data, Variables>): QueryRef<Data, Variables>; | ||
/** | ||
* `OnCompleteSubscription` | ||
*/ | ||
export declare type OnCompleteSubscription = () => void; | ||
/** | ||
* Representation of full observer options in `subscribe` | ||
*/ | ||
export interface SubscriptionOptions<Data, Variables> { | ||
@@ -46,0 +96,0 @@ onNext?: OnResultSubscription<Data, Variables>; |
@@ -38,2 +38,5 @@ /** | ||
} | ||
/** | ||
* Serialized RefInfo as a result of `QueryResult.toJSON().refInfo` | ||
*/ | ||
export interface RefInfo<Variables> { | ||
@@ -44,4 +47,7 @@ name: string; | ||
} | ||
/** | ||
* Serialized Ref as a result of `QueryResult.toJSON()` | ||
*/ | ||
export interface SerializedRef<Data, Variables> extends OpResult<Data> { | ||
refInfo: RefInfo<Variables>; | ||
} |
@@ -18,3 +18,3 @@ /** | ||
import { FirebaseError } from '@firebase/util'; | ||
export declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error'; | ||
export declare type DataConnectErrorCode = 'other' | 'already-initialized' | 'not-initialized' | 'not-supported' | 'invalid-argument' | 'partial-error' | 'unauthorized'; | ||
export declare type Code = DataConnectErrorCode; | ||
@@ -28,2 +28,3 @@ export declare const Code: { | ||
PARTIAL_ERROR: DataConnectErrorCode; | ||
UNAUTHORIZED: DataConnectErrorCode; | ||
}; | ||
@@ -30,0 +31,0 @@ /** An error returned by a DataConnect operation. */ |
@@ -17,3 +17,3 @@ /** | ||
*/ | ||
import { FirebaseOptions } from '@firebase/app'; | ||
import { FirebaseOptions } from '@firebase/app-types'; | ||
import { FirebaseAuthInternalName, FirebaseAuthTokenData } from '@firebase/auth-interop-types'; | ||
@@ -20,0 +20,0 @@ import { Provider } from '@firebase/component'; |
@@ -31,3 +31,3 @@ /** | ||
constructor(transport: DataConnectTransport); | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<unknown, unknown>; | ||
track<Data, Variables>(queryName: string, variables: Variables, initialCache?: OpResult<Data>): TrackedQuery<Data, Variables>; | ||
addSubscription<Data, Variables>(queryRef: OperationRef<Data, Variables>, onResultCallback: OnResultSubscription<Data, Variables>, onErrorCallback?: OnErrorSubscription, initialCache?: OpResult<Data>): () => void; | ||
@@ -34,0 +34,0 @@ executeQuery<Data, Variables>(queryRef: QueryRef<Data, Variables>): QueryPromise<Data, Variables>; |
@@ -18,5 +18,5 @@ /** | ||
export declare function initializeFetch(fetchImpl: typeof fetch): void; | ||
export declare function dcFetch<T, U>(url: string, body: U, { signal }: AbortController, accessToken: string | null): Promise<{ | ||
export declare function dcFetch<T, U>(url: string, body: U, { signal }: AbortController, appId: string | null, accessToken: string | null, appCheckToken: string | null, _isUsingGen: boolean): Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; |
@@ -18,3 +18,7 @@ /** | ||
import { DataConnectOptions, TransportOptions } from '../../api/DataConnect'; | ||
import { AppCheckTokenProvider } from '../../core/AppCheckTokenProvider'; | ||
import { AuthTokenProvider } from '../../core/FirebaseAuthProvider'; | ||
/** | ||
* @internal | ||
*/ | ||
export interface DataConnectTransport { | ||
@@ -37,11 +41,5 @@ invokeQuery<T, U>(queryName: string, body?: U): PromiseLike<{ | ||
} | ||
export interface QueryResponse<T> extends CancellableOperation<T> { | ||
} | ||
export interface MutationResponse<T> extends CancellableOperation<T> { | ||
} | ||
export interface Sender<T> { | ||
abort: () => void; | ||
send: () => Promise<T>; | ||
} | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, authProvider?: AuthTokenProvider, transportOptions?: TransportOptions) => DataConnectTransport; | ||
export * from '../../core/FirebaseAuthProvider'; | ||
/** | ||
* @internal | ||
*/ | ||
export declare type TransportClass = new (options: DataConnectOptions, apiKey?: string, appId?: string, authProvider?: AuthTokenProvider, appCheckProvider?: AppCheckTokenProvider, transportOptions?: TransportOptions, _isUsingGen?: boolean) => DataConnectTransport; |
@@ -18,2 +18,3 @@ /** | ||
import { DataConnectOptions, TransportOptions } from '../../api/DataConnect'; | ||
import { AppCheckTokenProvider } from '../../core/AppCheckTokenProvider'; | ||
import { AuthTokenProvider } from '../../core/FirebaseAuthProvider'; | ||
@@ -23,3 +24,6 @@ import { DataConnectTransport } from '.'; | ||
private apiKey?; | ||
private appId?; | ||
private authProvider?; | ||
private appCheckProvider?; | ||
private _isUsingGen; | ||
private _host; | ||
@@ -33,15 +37,25 @@ private _port; | ||
private _accessToken; | ||
private _authInitialized; | ||
constructor(options: DataConnectOptions, apiKey?: string | undefined, authProvider?: AuthTokenProvider | undefined, transportOptions?: TransportOptions | undefined); | ||
private _appCheckToken; | ||
private _lastToken; | ||
constructor(options: DataConnectOptions, apiKey?: string | undefined, appId?: string, authProvider?: AuthTokenProvider | undefined, appCheckProvider?: AppCheckTokenProvider | undefined, transportOptions?: TransportOptions | undefined, _isUsingGen?: boolean); | ||
get endpointUrl(): string; | ||
useEmulator(host: string, port?: number, isSecure?: boolean): void; | ||
onTokenChanged(newToken: string | null): void; | ||
getWithAuth(): Promise<string>; | ||
invokeQuery: <T, U = unknown>(queryName: string, body: U) => { | ||
then: any; | ||
}; | ||
invokeMutation: <T, U = unknown>(mutationName: string, body: U) => { | ||
then: any; | ||
cancel: () => void; | ||
}; | ||
getWithAuth(forceToken?: boolean): Promise<string>; | ||
_setLastToken(lastToken: string | null): void; | ||
withRetry<T>(promiseFactory: () => Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>, retry?: boolean): Promise<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeQuery: <T, U>(queryName: string, body?: U) => PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
invokeMutation: <T, U>(queryName: string, body?: U) => PromiseLike<{ | ||
data: T; | ||
errors: Error[]; | ||
}>; | ||
} |
{ | ||
"name": "@firebase/data-connect", | ||
"version": "0.0.2-dataconnect-preview.877f8b7d0", | ||
"version": "0.0.3-canary.beaa4dffb", | ||
"description": "", | ||
@@ -38,5 +38,6 @@ "author": "Firebase <firebase-support@google.com> (https://firebase.google.com/)", | ||
"test:ci": "node ../../scripts/run_tests_in_ci.js -s test:emulator", | ||
"test:all": "npm run test:node", | ||
"test:all": "run-p --npm-path npm lint test:unit", | ||
"test:browser": "karma start --single-run", | ||
"test:node": "TS_NODE_FILES=true TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/{,!(browser)/**/}*.test.ts' --file src/index.node.ts --config ../../config/mocharc.node.js", | ||
"test:unit": "TS_NODE_FILES=true TS_NODE_CACHE=NO TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --reporter lcovonly -- mocha 'test/unit/**/*.test.ts' --file src/index.node.ts --config ../../config/mocharc.node.js", | ||
"test:emulator": "ts-node --compiler-options='{\"module\":\"commonjs\"}' ../../scripts/emulator-testing/dataconnect-test-runner.ts", | ||
@@ -49,11 +50,14 @@ "api-report": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' ts-node ../../repo-scripts/prune-dts/extract-public-api.ts --package data-connect --packageRoot . --typescriptDts ./dist/src/index.d.ts --rollupDts ./dist/private.d.ts --untrimmedRollupDts ./dist/internal.d.ts --publicDts ./dist/public.d.ts && yarn api-report:api-json", | ||
"license": "Apache-2.0", | ||
"peerDependencies": { | ||
"@firebase/app": "0.10.11-canary.beaa4dffb" | ||
}, | ||
"dependencies": { | ||
"@firebase/auth-interop-types": "0.2.3-dataconnect-preview.877f8b7d0", | ||
"@firebase/component": "0.6.7-dataconnect-preview.877f8b7d0", | ||
"@firebase/logger": "0.4.2-dataconnect-preview.877f8b7d0", | ||
"@firebase/util": "1.9.6-dataconnect-preview.877f8b7d0", | ||
"@firebase/auth-interop-types": "0.2.3-canary.beaa4dffb", | ||
"@firebase/component": "0.6.9-canary.beaa4dffb", | ||
"@firebase/logger": "0.4.2-canary.beaa4dffb", | ||
"@firebase/util": "1.10.0-canary.beaa4dffb", | ||
"tslib": "^2.1.0" | ||
}, | ||
"devDependencies": { | ||
"@firebase/app": "0.10.3-dataconnect-preview.877f8b7d0", | ||
"@firebase/app": "0.10.11-canary.beaa4dffb", | ||
"rollup": "2.79.1", | ||
@@ -60,0 +64,0 @@ "rollup-plugin-typescript2": "0.31.2", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
761802
64
8460
6
+ Added@firebase/app@0.10.11-canary.beaa4dffb(transitive)
+ Added@firebase/auth-interop-types@0.2.3-canary.beaa4dffb(transitive)
+ Added@firebase/component@0.6.9-canary.beaa4dffb(transitive)
+ Added@firebase/logger@0.4.2-canary.beaa4dffb(transitive)
+ Added@firebase/util@1.10.0-canary.beaa4dffb(transitive)
+ Addedidb@7.1.1(transitive)
- Removed@firebase/auth-interop-types@0.2.3-dataconnect-preview.877f8b7d0(transitive)
- Removed@firebase/component@0.6.7-dataconnect-preview.877f8b7d0(transitive)
- Removed@firebase/logger@0.4.2-dataconnect-preview.877f8b7d0(transitive)
- Removed@firebase/util@1.9.6-dataconnect-preview.877f8b7d0(transitive)