cordova-plugin-contacts
Advanced tools
Comparing version 0.2.7 to 0.2.8
@@ -47,6 +47,15 @@ <!--- | ||
Edit manifest.webapp and add permissions field as described in [Manifest Docs](https://developer.mozilla.org/en-US/Apps/Developing/Manifest#permissions). | ||
Create __www/manifest.webapp__ as described in | ||
[Manifest Docs](https://developer.mozilla.org/en-US/Apps/Developing/Manifest). | ||
Add relevant permisions. | ||
There is also a need to change the webapp type to "privileged" - [Manifest Docs](https://developer.mozilla.org/en-US/Apps/Developing/Manifest#type). | ||
All privileged apps enforce [Content Security Policy](https://developer.mozilla.org/en-US/Apps/CSP) which forbids inline script. Initialize your application in another way. | ||
__WARNING__: All privileged apps enforce [Content Security Policy](https://developer.mozilla.org/en-US/Apps/CSP) which forbids inline script. Initialize your application in another way. | ||
"type": "privileged", | ||
"permissions": { | ||
"contacts": { | ||
"access": "readwrite", | ||
"description": "Describe why there is a need for such permission" | ||
} | ||
} | ||
@@ -81,2 +90,3 @@ ## navigator.contacts | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -127,2 +137,3 @@ - Windows Phone 7 and 8 | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -205,2 +216,3 @@ - Windows Phone 7 and 8 | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -284,2 +296,11 @@ - Windows Phone 7 and 8 | ||
### FirefoxOS Quirks | ||
- __categories__: Partially supported. Fields __pref__ and __type__ are returning `null` | ||
- __ims__: Not supported | ||
- __photos__: Not supported | ||
### iOS Quirks | ||
@@ -348,2 +369,3 @@ | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -404,2 +426,6 @@ - Windows Phone 7 and 8 | ||
### FirefoxOS Quirks | ||
- __formatted__: Currently not supported | ||
### iOS Quirks | ||
@@ -463,2 +489,3 @@ | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -523,2 +550,3 @@ - Windows Phone 7 and 8 | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -568,2 +596,6 @@ - Windows Phone 7 and 8 | ||
### FirefoxOS Quirks | ||
- __formatted__: Partially supported, and read-only. Returns a concatenation of `honorificPrefix`, `givenName`, `middleName`, `familyName`, and `honorificSuffix`. | ||
### iOS Quirks | ||
@@ -597,2 +629,3 @@ | ||
- BlackBerry 10 | ||
- Firefox OS | ||
- iOS | ||
@@ -641,2 +674,12 @@ - Windows Phone 7 and 8 | ||
### Firefox OS Quirks | ||
- __pref__: Not supported | ||
- __type__: Not supported | ||
- __department__: Not supported | ||
- Fields __name__ and __title__ stored in __org__ and __jobTitle__. | ||
### iOS Quirks | ||
@@ -643,0 +686,0 @@ |
{ | ||
"name": "cordova-plugin-contacts", | ||
"version": "0.2.7", | ||
"version": "0.2.8", | ||
"description": "Cordova Contacts Plugin", | ||
@@ -5,0 +5,0 @@ "cordova": { |
@@ -71,1 +71,5 @@ <!-- | ||
* B-5658 Add doc/index.md for Contacts plugin | ||
### 0.2.8 (Feb 05, 2014) | ||
* [CB-3208] FFOS docs updated | ||
* CB-4590 - chooseContact in CDVContacts crashes app |
@@ -22,4 +22,2 @@ /* | ||
// somehow call this function by this: | ||
// exec(success, fail, "Contacts", "save", [dupContact]); | ||
// Cordova contact definition: | ||
@@ -33,6 +31,18 @@ // http://cordova.apache.org/docs/en/2.5.0/cordova_contacts_contacts.md.html#Contact | ||
var ContactField = require('./ContactField'); | ||
var ContactAddress = require('./ContactAddress'); | ||
var ContactName = require('./ContactName'); | ||
// XXX: a hack to check if id is "empty". Cordova inserts a | ||
// string "this string is supposed to be a unique identifier that will | ||
// never show up on a device" if id is empty | ||
function _hasId(id) { | ||
if (!id || id.indexOf(' ') >= 0) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
function createMozillaFromCordova(contact) { | ||
// Extend mozContact prototype to provide update from Cordova | ||
mozContact.prototype.updateFromCordova = function(contact) { | ||
function exportContactFieldArray(contactFieldArray, key) { | ||
@@ -56,3 +66,11 @@ if (!key) { | ||
for (var key in addresses[i]) { | ||
addr[key] = addresses[i][key]; | ||
if (key == 'formatted' || key == 'id') { | ||
continue; | ||
} else if (key == 'type') { | ||
addr[key] = [addresses[i][key]]; | ||
} else if (key == 'country') { | ||
addr['countryName'] = addresses[i][key]; | ||
} else { | ||
addr[key] = addresses[i][key]; | ||
} | ||
} | ||
@@ -64,98 +82,234 @@ arr.push(addr); | ||
function exportPhoneNumbers(phoneNumbers) { | ||
var mozNumbers = []; | ||
for (var i=0; i < phoneNumbers.length; i++) { | ||
var number = phoneNumbers[i]; | ||
mozNumbers.push({ | ||
type: number.type, | ||
value: number.value, | ||
pref: number.pref | ||
}); | ||
function exportContactField(data) { | ||
var contactFields = []; | ||
for (var i=0; i < data.length; i++) { | ||
var item = data[i]; | ||
if (item.value) { | ||
var itemData = {value: item.value}; | ||
if (item.type) { | ||
itemData.type = [item.type]; | ||
} | ||
if (item.pref) { | ||
itemData.pref = item.pref; | ||
} | ||
contactFields.push(itemData); | ||
} | ||
} | ||
return mozNumbers; | ||
return contactFields; | ||
} | ||
// prepare mozContact object | ||
var moz = new mozContact(); | ||
if (contact.id) { | ||
moz.id = contact.id; | ||
} | ||
// adding simple fields [contactField, eventualMozContactField] | ||
var arrayFields = [['givenName'], ['familyName'], ['displayName', 'name']]; | ||
var simpleFields = [['honorificPrefix'], ['honorificSuffix'], ['nickname'], ['birthday', 'bday'], ['note']]; | ||
j = 0; while(field = arrayFields[j++]) { | ||
var nameFields = [['givenName'], ['familyName'], | ||
['honorificPrefix'], ['honorificSuffix'], | ||
['middleName', 'additionalName']]; | ||
var baseArrayFields = [['displayName', 'name'], ['nickname']]; | ||
var baseStringFields = []; | ||
var j = 0; while(field = nameFields[j++]) { | ||
if (contact.name[field[0]]) { | ||
moz[field[1] || field[0]] = contact.name[field[0]].split(' '); | ||
this[field[1] || field[0]] = contact.name[field[0]].split(' '); | ||
} | ||
} | ||
j = 0; while(field = simpleFields[j++]) { | ||
if (contact.name[field[0]]) { | ||
moz[field[1] || field[0]] = contact.name[field[0]]; | ||
j = 0; while(field = baseArrayFields[j++]) { | ||
if (contact[field[0]]) { | ||
this[field[1] || field[0]] = contact[field[0]].split(' '); | ||
} | ||
} | ||
j = 0; while(field = baseStringFields[j++]) { | ||
if (contact[field[0]]) { | ||
this[field[1] || field[0]] = contact[field[0]]; | ||
} | ||
} | ||
if (contact.birthday) { | ||
this.bday = new Date(contact.birthday); | ||
} | ||
if (contact.emails) { | ||
moz.email = exportContactFieldArray(contact.emails); | ||
var emails = exportContactField(contact.emails) | ||
this.email = emails; | ||
} | ||
if (contact.categories) { | ||
moz.category = exportContactFieldArray(contact.categories); | ||
this.category = exportContactFieldArray(contact.categories); | ||
} | ||
if (contact.addresses) { | ||
moz.adr = exportAddress(contact.addresses); | ||
this.adr = exportAddress(contact.addresses); | ||
} | ||
if (contact.phoneNumbers) { | ||
moz.tel = exportPhoneNumbers(contact.phoneNumbers); | ||
this.tel = exportContactField(contact.phoneNumbers); | ||
} | ||
if (contact.organizations) { | ||
moz.org = exportContactFieldArray(contact.organizations, 'name'); | ||
moz.jobTitle = exportContactFieldArray(contact.organizations, 'title'); | ||
// XXX: organizations are saved in 2 arrays - org and jobTitle | ||
// depending on the usecase it might generate issues | ||
// where wrong title will be added to an organization | ||
this.org = exportContactFieldArray(contact.organizations, 'name'); | ||
this.jobTitle = exportContactFieldArray(contact.organizations, 'title'); | ||
} | ||
/* Find out how to translate these parameters | ||
// photo: Blob | ||
// url: Array with metadata (?) | ||
// impp: exportIM(contact.ims), TODO: find the moz impp definition | ||
// anniversary | ||
// sex | ||
// genderIdentity | ||
// key | ||
*/ | ||
return moz; | ||
if (contact.note) { | ||
this.note = [contact.note]; | ||
} | ||
} | ||
function createCordovaFromMozilla(moz) { | ||
function exportPhoneNumbers(mozNumbers) { | ||
var phoneNumbers = []; | ||
for (var i=0; i < mozNumbers.length; i++) { | ||
var number = mozNumbers[i]; | ||
phoneNumbers.push( | ||
new ContactField( number.type, number.value, number.pref)); | ||
// Extend Cordova Contact prototype to provide update from FFOS contact | ||
Contact.prototype.updateFromMozilla = function(moz) { | ||
function exportContactField(data) { | ||
var contactFields = []; | ||
for (var i=0; i < data.length; i++) { | ||
var item = data[i]; | ||
var itemData = new ContactField(item.type, item.value, item.pref); | ||
contactFields.push(itemData); | ||
} | ||
return phoneNumbers; | ||
return contactFields; | ||
} | ||
var contact = new Contact(); | ||
function makeContactFieldFromArray(data) { | ||
var contactFields = []; | ||
for (var i=0; i < data.length; i++) { | ||
var itemData = new ContactField(null, data[i]); | ||
contactFields.push(itemData); | ||
} | ||
return contactFields; | ||
} | ||
function exportAddresses(addresses) { | ||
// TODO: check moz address format | ||
var arr = []; | ||
for (var i=0; i < addresses.length; i++) { | ||
var addr = {}; | ||
for (var key in addresses[i]) { | ||
if (key == 'countryName') { | ||
addr['country'] = addresses[i][key]; | ||
} else if (key == 'type') { | ||
addr[key] = addresses[i][key].join(' '); | ||
} else { | ||
addr[key] = addresses[i][key]; | ||
} | ||
} | ||
arr.push(addr); | ||
} | ||
return arr; | ||
} | ||
function createOrganizations(orgs, jobs) { | ||
orgs = (orgs) ? orgs : []; | ||
jobs = (jobs) ? jobs : []; | ||
var max_length = Math.max(orgs.length, jobs.length); | ||
var organizations = []; | ||
for (var i=0; i < max_length; i++) { | ||
organizations.push(new ContactOrganization( | ||
null, null, orgs[i] || null, null, jobs[i] || null)); | ||
} | ||
return organizations; | ||
} | ||
function createFormatted(name) { | ||
var fields = ['honorificPrefix', 'givenName', 'middleName', | ||
'familyName', 'honorificSuffix']; | ||
var f = ''; | ||
for (var i = 0; i < fields.length; i++) { | ||
if (name[fields[i]]) { | ||
if (f) { | ||
f += ' '; | ||
} | ||
f += name[fields[i]]; | ||
} | ||
} | ||
return f; | ||
} | ||
if (moz.id) { | ||
contact.id = moz.id; | ||
this.id = moz.id; | ||
} | ||
var arrayFields = [['givenName'], ['familyName'], ['name', 'displayName']]; | ||
var simpleFields = [['honorificPrefix'], ['honorificSuffix'], ['nickname'], ['bday', 'birthday'], ['note']]; | ||
var nameFields = [['givenName'], ['familyName'], | ||
['honorificPrefix'], ['honorificSuffix'], | ||
['additionalName', 'middleName']]; | ||
var baseArrayFields = [['name', 'displayName'], 'nickname', ['note']]; | ||
var baseStringFields = []; | ||
var name = new ContactName(); | ||
var j = 0; while(field = arrayFields[j++]) { | ||
if (moz[field[0]]) { | ||
name[field[1] || field[0]] = moz[field[0]].join(' '); | ||
} | ||
var j = 0; while(field = nameFields[j++]) { | ||
if (moz[field[0]]) { | ||
name[field[1] || field[0]] = moz[field[0]].join(' '); | ||
} | ||
} | ||
j = 0; while(field = simpleFields[j++]) { | ||
if (moz[field[0]]) { | ||
name[field[1] || field[0]] = moz[field[0]]; | ||
} | ||
this.name = name; | ||
j = 0; while(field = baseArrayFields[j++]) { | ||
if (moz[field[0]]) { | ||
this[field[1] || field[0]] = moz[field[0]].join(' '); | ||
} | ||
} | ||
contact.name = name; | ||
j = 0; while(field = baseStringFields[j++]) { | ||
if (moz[field[0]]) { | ||
this[field[1] || field[0]] = moz[field[0]]; | ||
} | ||
} | ||
// emails | ||
if (moz.email) { | ||
this.emails = exportContactField(moz.email); | ||
} | ||
// categories | ||
if (moz.category) { | ||
this.categories = makeContactFieldFromArray(moz.category); | ||
} | ||
// addresses | ||
if (moz.adr) { | ||
this.addresses = exportAddresses(moz.adr); | ||
} | ||
// phoneNumbers | ||
if (moz.tel) { | ||
contact.phoneNumbers = exportPhoneNumbers(moz.tel); | ||
this.phoneNumbers = exportContactField(moz.tel); | ||
} | ||
// birthday | ||
if (moz.bday) { | ||
this.birthday = Date.parse(moz.bday); | ||
} | ||
// organizations | ||
if (moz.org || moz.jobTitle) { | ||
// XXX: organizations array is created from org and jobTitle | ||
this.organizations = createOrganizations(moz.org, moz.jobTitle); | ||
} | ||
// construct a read-only formatted value | ||
this.name.formatted = createFormatted(this.name); | ||
/* Find out how to translate these parameters | ||
// photo: Blob | ||
// url: Array with metadata (?) | ||
// impp: exportIM(contact.ims), TODO: find the moz impp definition | ||
// anniversary | ||
// sex | ||
// genderIdentity | ||
// key | ||
*/ | ||
} | ||
function createMozillaFromCordova(successCB, errorCB, contact) { | ||
var moz; | ||
// get contact if exists | ||
if (_hasId(contact.id)) { | ||
var search = navigator.mozContacts.find({ | ||
filterBy: ['id'], filterValue: contact.id, filterOp: 'equals'}); | ||
search.onsuccess = function() { | ||
moz = search.result[0]; | ||
moz.updateFromCordova(contact); | ||
successCB(moz); | ||
}; | ||
search.onerror = errorCB; | ||
return; | ||
} | ||
// create empty contact | ||
moz = new mozContact(); | ||
if ('init' in moz) { | ||
// 1.2 and below compatibility | ||
moz.init(); | ||
} | ||
moz.updateFromCordova(contact); | ||
successCB(moz); | ||
} | ||
function createCordovaFromMozilla(moz) { | ||
var contact = new Contact(); | ||
contact.updateFromMozilla(moz); | ||
return contact; | ||
@@ -165,2 +319,4 @@ } | ||
// However API requires the ability to save multiple contacts, it is | ||
// used to save only one element array | ||
function saveContacts(successCB, errorCB, contacts) { | ||
@@ -180,7 +336,8 @@ // a closure which is holding the right moz contact | ||
while(contact = contacts[i++]){ | ||
var moz = createMozillaFromCordova(contact); | ||
var request = navigator.mozContacts.save(moz); | ||
// success and/or fail will be called every time a contact is saved | ||
request.onsuccess = makeSaveSuccessCB(moz); | ||
request.onerror = errorCB; | ||
var moz = createMozillaFromCordova(function(moz) { | ||
var request = navigator.mozContacts.save(moz); | ||
// success and/or fail will be called every time a contact is saved | ||
request.onsuccess = makeSaveSuccessCB(moz); | ||
request.onerror = errorCB; | ||
}, function() {}, contact); | ||
} | ||
@@ -190,2 +347,3 @@ } | ||
// API provides a list of ids to be removed | ||
function remove(successCB, errorCB, ids) { | ||
@@ -195,7 +353,23 @@ var i=0; | ||
for (var i=0; i < ids.length; i++){ | ||
var moz = new mozContact(); | ||
moz.id = ids[i]; | ||
var request = navigator.mozContacts.remove(moz); | ||
request.onsuccess = successCB; | ||
request.onerror = errorCB; | ||
// throw an error if no id provided | ||
if (!_hasId(ids[i])) { | ||
console.error('FFOS: Attempt to remove unsaved contact'); | ||
errorCB(0); | ||
return; | ||
} | ||
// check if provided id actually exists | ||
var search = navigator.mozContacts.find({ | ||
filterBy: ['id'], filterValue: ids[i], filterOp: 'equals'}); | ||
search.onsuccess = function() { | ||
if (search.result.length === 0) { | ||
console.error('FFOS: Attempt to remove a non existing contact'); | ||
errorCB(0); | ||
return; | ||
} | ||
var moz = search.result[0]; | ||
var request = navigator.mozContacts.remove(moz); | ||
request.onsuccess = successCB; | ||
request.onerror = errorCB; | ||
}; | ||
search.onerror = errorCB; | ||
} | ||
@@ -205,95 +379,36 @@ } | ||
var mozContactSearchFields = ['name', 'givenName', 'additionalName', | ||
'familyName', 'nickname', 'email', 'tel', 'jobTitle', 'note']; | ||
var mozContactSearchFields = [['name', 'displayName'], ['givenName'], | ||
['familyName'], ['email'], ['tel'], ['jobTitle'], ['note'], | ||
['tel', 'phoneNumbers'], ['email', 'emails']]; | ||
// Searching by nickname and additionalName is forbidden in 1.3 and below | ||
// Searching by name is forbidden in 1.2 and below | ||
// function search(successCB, errorCB, params) { | ||
// var options = params[1] || {}; | ||
// var filter = []; | ||
// // filter out inallowed fields | ||
// for (var i=0; i < params[0].length; i++) { | ||
// if (mozContactSearchFields.indexOf([params[0][i]])) { | ||
// filter.push(params[0][i]); | ||
// } else if (params[0][i] == 'displayName') { | ||
// filter.push('name'); | ||
// } else { | ||
// console.log('FXOS ContactProxy: inallowed field passed to search filtered out: ' + params[0][i]); | ||
// } | ||
// } | ||
// | ||
// var request; | ||
// // TODO find out how to handle searching by numbers | ||
// // filterOp: The filter comparison operator to use. Possible values are | ||
// // equals, startsWith, and match, the latter being specific | ||
// // to telephone numbers. | ||
// var mozOptions = {filterBy: filter, filterOp: 'startsWith'}; | ||
// if (!options.multiple) { | ||
// mozOptions.filterLimit = 1; | ||
// } | ||
// if (!options.filter) { | ||
// // this is returning 0 contacts | ||
// request = navigator.mozContacts.getAll({}); | ||
// } else { | ||
// // XXX This is searching for regardless of the filterValue !!! | ||
// mozOptions.filterValue = options.filter; | ||
// console.log('mozoptions: filterBy: ' + mozOptions.filterBy.join(' ') + '; fiterValue: ' + mozOptions.filterValue); | ||
// request = navigator.mozContacts.find(mozOptions); | ||
// } | ||
// request.onsuccess = function() { | ||
// var contacts = []; | ||
// var mozContacts = request.result; | ||
// for (var i=0; i < mozContacts.length; i++) { | ||
// contacts.push(createCordovaFromMozilla(mozContacts[i])); | ||
// } | ||
// successCB(contacts); | ||
// }; | ||
// request.onerror = errorCB; | ||
// } | ||
// finds if a key is allowed and returns FFOS name if different | ||
function getMozSearchField(key) { | ||
if (mozContactSearchFields.indexOf([key]) >= 0) { | ||
return key; | ||
} | ||
for (var i=0; i < mozContactSearchFields.length; i++) { | ||
if (mozContactSearchFields[i].length > 1) { | ||
if (mozContactSearchFields[i][1] === key) { | ||
return mozContactSearchFields[i][0]; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
/* navigator.mozContacts.find has issues - using getAll | ||
* https://bugzilla.mozilla.org/show_bug.cgi?id=941008 | ||
*/ | ||
function hackedSearch(successCB, errorCB, params) { | ||
function _getAll(successCB, errorCB, params) { | ||
// [contactField, eventualMozContactField] | ||
var arrayFields = ['givenName', 'familyName', 'name']; | ||
var options = params[1] || {}; | ||
var filter = []; | ||
// filter out inallowed fields | ||
for (var i=0; i < params[0].length; i++) { | ||
if (mozContactSearchFields.indexOf([params[0][i]])) { | ||
filter.push(params[0][i]); | ||
} else if (params[0][i] == 'displayName') { | ||
filter.push('name'); | ||
} else { | ||
console.log('FXOS ContactProxy: inallowed field passed to search filtered out: ' + params[0][i]); | ||
} | ||
} | ||
var getall = navigator.mozContacts.getAll({}); | ||
var contacts = []; | ||
function isValid(mozContact) { | ||
if (!options.filter) { | ||
// get all | ||
return true; | ||
} | ||
for (var j=0; j < filter.length; j++) { | ||
var field = filter[0]; | ||
var value = (arrayFields.indexOf(field) >= 0) ? mozContact[field].join(' ') : mozContact[field]; | ||
if (value.indexOf(options.filter) >= 0) { | ||
return true; | ||
} | ||
} | ||
} | ||
getall.onsuccess = function() { | ||
if (getall.result) { | ||
if (isValid(getall.result)) { | ||
contacts.push(createCordovaFromMozilla(getall.result)); | ||
} | ||
contacts.push(createCordovaFromMozilla(getall.result)); | ||
getall.continue(); | ||
} else { | ||
successCB(contacts); | ||
} | ||
}; | ||
@@ -303,8 +418,57 @@ getall.onerror = errorCB; | ||
function search(successCB, errorCB, params) { | ||
var options = params[1] || {}; | ||
if (!options.filter) { | ||
return _getAll(successCB, errorCB, params); | ||
} | ||
var filterBy = []; | ||
// filter and translate fields | ||
for (var i=0; i < params[0].length; i++) { | ||
var searchField = params[0][i]; | ||
var mozField = getMozSearchField(searchField); | ||
if (searchField === 'name') { | ||
// Cordova uses name for search by all name fields. | ||
filterBy.push('givenName'); | ||
filterBy.push('familyName'); | ||
continue; | ||
} | ||
if (searchField === 'displayName' && 'init' in new mozContact()) { | ||
// ``init`` in ``mozContact`` indicates FFOS version 1.2 or below | ||
// Searching by name (in moz) is then forbidden | ||
console.log('FFOS ContactProxy: Unable to search by displayName on FFOS 1.2'); | ||
continue; | ||
} | ||
if (mozField) { | ||
filterBy.push(mozField); | ||
} else { | ||
console.log('FXOS ContactProxy: inallowed field passed to search filtered out: ' + searchField); | ||
} | ||
} | ||
var mozOptions = {filterBy: filterBy, filterOp: 'startsWith'}; | ||
if (!options.multiple) { | ||
mozOptions.filterLimit = 1; | ||
} | ||
mozOptions.filterValue = options.filter; | ||
var request = navigator.mozContacts.find(mozOptions); | ||
request.onsuccess = function() { | ||
var contacts = []; | ||
var mozContacts = request.result; | ||
var moz = mozContacts[0]; | ||
for (var i=0; i < mozContacts.length; i++) { | ||
contacts.push(createCordovaFromMozilla(mozContacts[i])); | ||
} | ||
successCB(contacts); | ||
}; | ||
request.onerror = errorCB; | ||
} | ||
module.exports = { | ||
save: saveContacts, | ||
remove: remove, | ||
search: hackedSearch | ||
search: search | ||
}; | ||
require("cordova/firefoxos/commandProxy").add("Contacts", module.exports); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
418454
40
2037
1