@firebase/data-connect 0.0.2-dataconnect-preview.388b61c7e → 0.0.3-dataconnect-preview.d986d4bf2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.js +146 -27
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm2017.js +145 -28
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +146 -23
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +147 -22
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/internal.d.ts +32 -5
- package/dist/node-esm/index.node.esm.js +145 -28
- package/dist/node-esm/index.node.esm.js.map +1 -1
- package/dist/node-esm/src/api/DataConnect.d.ts +9 -0
- package/dist/node-esm/src/api/index.d.ts +1 -0
- package/dist/node-esm/src/api/query.d.ts +1 -1
- package/dist/node-esm/src/core/FirebaseAuthProvider.d.ts +1 -1
- package/dist/node-esm/src/core/QueryManager.d.ts +1 -1
- package/dist/node-esm/src/core/error.d.ts +2 -1
- package/dist/node-esm/src/network/fetch.d.ts +1 -1
- package/dist/node-esm/src/network/transport/index.d.ts +1 -1
- package/dist/node-esm/src/network/transport/rest.d.ts +20 -9
- package/dist/node-esm/src/util/validateArgs.d.ts +33 -0
- package/dist/private.d.ts +16 -5
- package/dist/public.d.ts +5 -3
- package/dist/src/api/DataConnect.d.ts +9 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/query.d.ts +1 -1
- package/dist/src/core/FirebaseAuthProvider.d.ts +1 -1
- package/dist/src/core/QueryManager.d.ts +1 -1
- package/dist/src/core/error.d.ts +2 -1
- package/dist/src/network/fetch.d.ts +1 -1
- package/dist/src/network/transport/index.d.ts +1 -1
- package/dist/src/network/transport/rest.d.ts +20 -9
- package/dist/src/util/validateArgs.d.ts +33 -0
- package/package.json +10 -6
package/dist/index.cjs.js
CHANGED
|
@@ -8,7 +8,7 @@ var util = require('@firebase/util');
|
|
|
8
8
|
var logger$1 = require('@firebase/logger');
|
|
9
9
|
|
|
10
10
|
const name = "@firebase/data-connect";
|
|
11
|
-
const version = "0.0.
|
|
11
|
+
const version = "0.0.3-dataconnect-preview.d986d4bf2";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @license
|
|
@@ -58,7 +58,8 @@ const Code = {
|
|
|
58
58
|
NOT_INITIALIZED: 'not-initialized',
|
|
59
59
|
NOT_SUPPORTED: 'not-supported',
|
|
60
60
|
INVALID_ARGUMENT: 'invalid-argument',
|
|
61
|
-
PARTIAL_ERROR: 'partial-error'
|
|
61
|
+
PARTIAL_ERROR: 'partial-error',
|
|
62
|
+
UNAUTHORIZED: 'unauthorized'
|
|
62
63
|
};
|
|
63
64
|
/** An error returned by a DataConnect operation. */
|
|
64
65
|
class DataConnectError extends util.FirebaseError {
|
|
@@ -167,7 +168,8 @@ class FirebaseAuthProvider {
|
|
|
167
168
|
removeTokenChangeListener(listener) {
|
|
168
169
|
this._authProvider
|
|
169
170
|
.get()
|
|
170
|
-
.then(auth => auth.removeAuthTokenListener(listener))
|
|
171
|
+
.then(auth => auth.removeAuthTokenListener(listener))
|
|
172
|
+
.catch(err => logError(err));
|
|
171
173
|
}
|
|
172
174
|
}
|
|
173
175
|
|
|
@@ -435,12 +437,20 @@ function addToken(url, apiKey) {
|
|
|
435
437
|
* limitations under the License.
|
|
436
438
|
*/
|
|
437
439
|
let connectFetch = globalThis.fetch;
|
|
438
|
-
function
|
|
440
|
+
function getGoogApiClientValue(_isUsingGen) {
|
|
441
|
+
let str = 'gl-js/ fire/' + SDK_VERSION;
|
|
442
|
+
if (_isUsingGen) {
|
|
443
|
+
str += ' web/gen';
|
|
444
|
+
}
|
|
445
|
+
return str;
|
|
446
|
+
}
|
|
447
|
+
function dcFetch(url, body, { signal }, accessToken, _isUsingGen) {
|
|
439
448
|
if (!connectFetch) {
|
|
440
449
|
throw new DataConnectError(Code.OTHER, 'No Fetch Implementation detected!');
|
|
441
450
|
}
|
|
442
451
|
const headers = {
|
|
443
|
-
'Content-Type': 'application/json'
|
|
452
|
+
'Content-Type': 'application/json',
|
|
453
|
+
'X-Goog-Api-Client': getGoogApiClientValue(_isUsingGen)
|
|
444
454
|
};
|
|
445
455
|
if (accessToken) {
|
|
446
456
|
headers['X-Firebase-Auth-Token'] = accessToken;
|
|
@@ -452,8 +462,9 @@ function dcFetch(url, body, { signal }, accessToken) {
|
|
|
452
462
|
method: 'POST',
|
|
453
463
|
headers,
|
|
454
464
|
signal
|
|
455
|
-
})
|
|
456
|
-
|
|
465
|
+
})
|
|
466
|
+
.catch(err => {
|
|
467
|
+
throw new DataConnectError(Code.OTHER, 'Failed to fetch: ' + JSON.stringify(err));
|
|
457
468
|
})
|
|
458
469
|
.then(async (response) => {
|
|
459
470
|
let jsonResponse = null;
|
|
@@ -463,9 +474,13 @@ function dcFetch(url, body, { signal }, accessToken) {
|
|
|
463
474
|
catch (e) {
|
|
464
475
|
throw new DataConnectError(Code.OTHER, JSON.stringify(e));
|
|
465
476
|
}
|
|
477
|
+
const message = getMessage(jsonResponse);
|
|
466
478
|
if (response.status >= 400) {
|
|
467
479
|
logError('Error while performing request: ' + JSON.stringify(jsonResponse));
|
|
468
|
-
|
|
480
|
+
if (response.status === 401) {
|
|
481
|
+
throw new DataConnectError(Code.UNAUTHORIZED, message);
|
|
482
|
+
}
|
|
483
|
+
throw new DataConnectError(Code.OTHER, message);
|
|
469
484
|
}
|
|
470
485
|
return jsonResponse;
|
|
471
486
|
})
|
|
@@ -477,6 +492,12 @@ function dcFetch(url, body, { signal }, accessToken) {
|
|
|
477
492
|
}
|
|
478
493
|
return res;
|
|
479
494
|
});
|
|
495
|
+
}
|
|
496
|
+
function getMessage(obj) {
|
|
497
|
+
if ('message' in obj) {
|
|
498
|
+
return obj.message;
|
|
499
|
+
}
|
|
500
|
+
return JSON.stringify(obj);
|
|
480
501
|
}
|
|
481
502
|
|
|
482
503
|
/**
|
|
@@ -496,10 +517,11 @@ function dcFetch(url, body, { signal }, accessToken) {
|
|
|
496
517
|
* limitations under the License.
|
|
497
518
|
*/
|
|
498
519
|
class RESTTransport {
|
|
499
|
-
constructor(options, apiKey, authProvider, transportOptions) {
|
|
520
|
+
constructor(options, apiKey, authProvider, transportOptions, _isUsingGen = false) {
|
|
500
521
|
var _a;
|
|
501
522
|
this.apiKey = apiKey;
|
|
502
523
|
this.authProvider = authProvider;
|
|
524
|
+
this._isUsingGen = _isUsingGen;
|
|
503
525
|
this._host = '';
|
|
504
526
|
this._location = 'l';
|
|
505
527
|
this._connectorName = '';
|
|
@@ -507,30 +529,30 @@ class RESTTransport {
|
|
|
507
529
|
this._project = 'p';
|
|
508
530
|
this._accessToken = null;
|
|
509
531
|
this._authInitialized = false;
|
|
532
|
+
this._lastToken = null;
|
|
510
533
|
// TODO(mtewani): Update U to include shape of body defined in line 13.
|
|
511
534
|
this.invokeQuery = (queryName, body) => {
|
|
512
535
|
const abortController = new AbortController();
|
|
513
536
|
// TODO(mtewani): Update to proper value
|
|
514
|
-
const withAuth = this.
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
abortController, this._accessToken);
|
|
521
|
-
});
|
|
537
|
+
const withAuth = this.withRetry(() => dcFetch(addToken(`${this.endpointUrl}:executeQuery`, this.apiKey), {
|
|
538
|
+
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`,
|
|
539
|
+
operationName: queryName,
|
|
540
|
+
variables: body
|
|
541
|
+
}, // TODO(mtewani): This is a patch, fix this.
|
|
542
|
+
abortController, this._accessToken, this._isUsingGen));
|
|
522
543
|
return {
|
|
523
|
-
then: withAuth.then.bind(withAuth)
|
|
544
|
+
then: withAuth.then.bind(withAuth),
|
|
545
|
+
catch: withAuth.catch.bind(withAuth)
|
|
524
546
|
};
|
|
525
547
|
};
|
|
526
548
|
this.invokeMutation = (mutationName, body) => {
|
|
527
549
|
const abortController = new AbortController();
|
|
528
|
-
const taskResult = this.
|
|
550
|
+
const taskResult = this.withRetry(() => {
|
|
529
551
|
return dcFetch(addToken(`${this.endpointUrl}:executeMutation`, this.apiKey), {
|
|
530
552
|
name: `projects/${this._project}/locations/${this._location}/services/${this._serviceName}/connectors/${this._connectorName}`,
|
|
531
553
|
operationName: mutationName,
|
|
532
554
|
variables: body
|
|
533
|
-
}, abortController, this._accessToken);
|
|
555
|
+
}, abortController, this._accessToken, this._isUsingGen);
|
|
534
556
|
});
|
|
535
557
|
return {
|
|
536
558
|
then: taskResult.then.bind(taskResult),
|
|
@@ -585,12 +607,12 @@ class RESTTransport {
|
|
|
585
607
|
onTokenChanged(newToken) {
|
|
586
608
|
this._accessToken = newToken;
|
|
587
609
|
}
|
|
588
|
-
getWithAuth() {
|
|
610
|
+
getWithAuth(forceToken = false) {
|
|
589
611
|
let starterPromise = new Promise(resolve => resolve(this._accessToken));
|
|
590
612
|
if (!this._authInitialized) {
|
|
591
613
|
if (this.authProvider) {
|
|
592
614
|
starterPromise = this.authProvider
|
|
593
|
-
.getToken(/*forceToken=*/
|
|
615
|
+
.getToken(/*forceToken=*/ forceToken)
|
|
594
616
|
.then(data => {
|
|
595
617
|
if (!data) {
|
|
596
618
|
return null;
|
|
@@ -605,6 +627,30 @@ class RESTTransport {
|
|
|
605
627
|
}
|
|
606
628
|
return starterPromise;
|
|
607
629
|
}
|
|
630
|
+
_setLastToken(lastToken) {
|
|
631
|
+
this._lastToken = lastToken;
|
|
632
|
+
}
|
|
633
|
+
withRetry(promiseFactory, retry = false) {
|
|
634
|
+
let isNewToken = false;
|
|
635
|
+
return this.getWithAuth(retry)
|
|
636
|
+
.then(res => {
|
|
637
|
+
isNewToken = this._lastToken !== res;
|
|
638
|
+
this._lastToken = res;
|
|
639
|
+
return res;
|
|
640
|
+
})
|
|
641
|
+
.then(promiseFactory)
|
|
642
|
+
.catch(err => {
|
|
643
|
+
// Only retry if the result is unauthorized and the last token isn't the same as the new one.
|
|
644
|
+
if ('code' in err &&
|
|
645
|
+
err.code === Code.UNAUTHORIZED &&
|
|
646
|
+
!retry &&
|
|
647
|
+
isNewToken) {
|
|
648
|
+
logDebug('Retrying due to unauthorized');
|
|
649
|
+
return this.withRetry(promiseFactory, true);
|
|
650
|
+
}
|
|
651
|
+
throw err;
|
|
652
|
+
});
|
|
653
|
+
}
|
|
608
654
|
}
|
|
609
655
|
|
|
610
656
|
/**
|
|
@@ -711,6 +757,7 @@ class DataConnect {
|
|
|
711
757
|
this._authProvider = _authProvider;
|
|
712
758
|
this.isEmulator = false;
|
|
713
759
|
this.initialized = false;
|
|
760
|
+
this._isUsingGeneratedSdk = false;
|
|
714
761
|
if (typeof process !== 'undefined' && process.env) {
|
|
715
762
|
const host = process.env[FIREBASE_DATA_CONNECT_EMULATOR_HOST_VAR];
|
|
716
763
|
if (host) {
|
|
@@ -720,6 +767,14 @@ class DataConnect {
|
|
|
720
767
|
}
|
|
721
768
|
}
|
|
722
769
|
}
|
|
770
|
+
/*
|
|
771
|
+
@internal
|
|
772
|
+
*/
|
|
773
|
+
_useGeneratedSdk() {
|
|
774
|
+
if (!this._isUsingGeneratedSdk) {
|
|
775
|
+
this._isUsingGeneratedSdk = true;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
723
778
|
_delete() {
|
|
724
779
|
app._removeServiceInstance(this.app, 'data-connect', JSON.stringify(this.getSettings()));
|
|
725
780
|
return Promise.resolve();
|
|
@@ -741,7 +796,7 @@ class DataConnect {
|
|
|
741
796
|
this._authTokenProvider = new FirebaseAuthProvider(this.app.name, this.app.options, this._authProvider);
|
|
742
797
|
}
|
|
743
798
|
this.initialized = true;
|
|
744
|
-
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider);
|
|
799
|
+
this._transport = new this._transportClass(this.dataConnectOptions, this.app.options.apiKey, this._authTokenProvider, undefined, this._isUsingGeneratedSdk);
|
|
745
800
|
if (this._transportOptions) {
|
|
746
801
|
this._transport.useEmulator(this._transportOptions.host, this._transportOptions.port, this._transportOptions.sslEnabled);
|
|
747
802
|
}
|
|
@@ -778,7 +833,7 @@ function getDataConnect(appOrOptions, optionalOptions) {
|
|
|
778
833
|
dcOptions = optionalOptions;
|
|
779
834
|
app$1 = appOrOptions;
|
|
780
835
|
}
|
|
781
|
-
if (!app$1) {
|
|
836
|
+
if (!app$1 || Object.keys(app$1).length === 0) {
|
|
782
837
|
app$1 = app.getApp();
|
|
783
838
|
}
|
|
784
839
|
const provider = app._getProvider(app$1, 'data-connect');
|
|
@@ -792,9 +847,7 @@ function getDataConnect(appOrOptions, optionalOptions) {
|
|
|
792
847
|
return dcInstance;
|
|
793
848
|
}
|
|
794
849
|
}
|
|
795
|
-
|
|
796
|
-
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required');
|
|
797
|
-
}
|
|
850
|
+
validateDCOptions(dcOptions);
|
|
798
851
|
logDebug('Creating new DataConnect instance');
|
|
799
852
|
// Initialize with options.
|
|
800
853
|
return provider.initialize({
|
|
@@ -802,6 +855,24 @@ function getDataConnect(appOrOptions, optionalOptions) {
|
|
|
802
855
|
options: dcOptions
|
|
803
856
|
});
|
|
804
857
|
}
|
|
858
|
+
/**
|
|
859
|
+
*
|
|
860
|
+
* @param dcOptions
|
|
861
|
+
* @returns {void}
|
|
862
|
+
* @internal
|
|
863
|
+
*/
|
|
864
|
+
function validateDCOptions(dcOptions) {
|
|
865
|
+
const fields = ['connector', 'location', 'service'];
|
|
866
|
+
if (!dcOptions) {
|
|
867
|
+
throw new DataConnectError(Code.INVALID_ARGUMENT, 'DC Option Required');
|
|
868
|
+
}
|
|
869
|
+
fields.forEach(field => {
|
|
870
|
+
if (dcOptions[field] === null || dcOptions[field] === undefined) {
|
|
871
|
+
throw new DataConnectError(Code.INVALID_ARGUMENT, `${field} Required`);
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
return true;
|
|
875
|
+
}
|
|
805
876
|
/**
|
|
806
877
|
* Delete DataConnect instance
|
|
807
878
|
* @param dataConnect DataConnect instance
|
|
@@ -837,6 +908,9 @@ function registerDataConnect(variant) {
|
|
|
837
908
|
if (settings) {
|
|
838
909
|
newOpts = JSON.parse(settings);
|
|
839
910
|
}
|
|
911
|
+
if (!app.options.projectId) {
|
|
912
|
+
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Project ID must be provided. Did you pass in a proper projectId to initializeApp?');
|
|
913
|
+
}
|
|
840
914
|
return new DataConnect(app, Object.assign(Object.assign({}, newOpts), { projectId: app.options.projectId }), authProvider);
|
|
841
915
|
}, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
|
|
842
916
|
app.registerVersion(name, version, variant);
|
|
@@ -896,6 +970,49 @@ function toQueryRef(serializedRef) {
|
|
|
896
970
|
return queryRef(getDataConnect(connectorConfig), name, variables);
|
|
897
971
|
}
|
|
898
972
|
|
|
973
|
+
/**
|
|
974
|
+
* @license
|
|
975
|
+
* Copyright 2024 Google LLC
|
|
976
|
+
*
|
|
977
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
978
|
+
* you may not use this file except in compliance with the License.
|
|
979
|
+
* You may obtain a copy of the License at
|
|
980
|
+
*
|
|
981
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
982
|
+
*
|
|
983
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
984
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
985
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
986
|
+
* See the License for the specific language governing permissions and
|
|
987
|
+
* limitations under the License.
|
|
988
|
+
*/
|
|
989
|
+
/**
|
|
990
|
+
* The generated SDK will allow the user to pass in either the variable or the data connect instance with the variable,
|
|
991
|
+
* and this function validates the variables and returns back the DataConnect instance and variables based on the arguments passed in.
|
|
992
|
+
* @param connectorConfig
|
|
993
|
+
* @param dcOrVars
|
|
994
|
+
* @param vars
|
|
995
|
+
* @param validateVars
|
|
996
|
+
* @returns {DataConnect} and {Variables} instance
|
|
997
|
+
* @internal
|
|
998
|
+
*/
|
|
999
|
+
function validateArgs(connectorConfig, dcOrVars, vars, validateVars) {
|
|
1000
|
+
let dcInstance;
|
|
1001
|
+
let realVars;
|
|
1002
|
+
if (dcOrVars && 'enableEmulator' in dcOrVars) {
|
|
1003
|
+
dcInstance = dcOrVars;
|
|
1004
|
+
realVars = vars;
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
dcInstance = getDataConnect(connectorConfig);
|
|
1008
|
+
realVars = dcOrVars;
|
|
1009
|
+
}
|
|
1010
|
+
if (!dcInstance || (!realVars && validateVars)) {
|
|
1011
|
+
throw new DataConnectError(Code.INVALID_ARGUMENT, 'Variables required.');
|
|
1012
|
+
}
|
|
1013
|
+
return { dc: dcInstance, vars: realVars };
|
|
1014
|
+
}
|
|
1015
|
+
|
|
899
1016
|
/**
|
|
900
1017
|
* @license
|
|
901
1018
|
* Copyright 2024 Google LLC
|
|
@@ -977,4 +1094,6 @@ exports.setLogLevel = setLogLevel;
|
|
|
977
1094
|
exports.subscribe = subscribe;
|
|
978
1095
|
exports.terminate = terminate;
|
|
979
1096
|
exports.toQueryRef = toQueryRef;
|
|
1097
|
+
exports.validateArgs = validateArgs;
|
|
1098
|
+
exports.validateDCOptions = validateDCOptions;
|
|
980
1099
|
//# sourceMappingURL=index.cjs.js.map
|