|
|
|
@@ -200,6 +200,12 @@ const {
|
|
|
|
|
buildAvatarDecorationExportJsonBody,
|
|
|
|
|
signAvatarDecorationExportJson,
|
|
|
|
|
verifyAvatarDecorationExportJson,
|
|
|
|
|
buildDeviceSyncJsonBody,
|
|
|
|
|
signDeviceSyncJson,
|
|
|
|
|
verifyDeviceSyncJson,
|
|
|
|
|
buildDiscoveryListingExportJsonBody,
|
|
|
|
|
signDiscoveryListingExportJson,
|
|
|
|
|
verifyDiscoveryListingExportJson,
|
|
|
|
|
formatAutomationScheduleDigestExport,
|
|
|
|
|
mergeHookFailureDigests,
|
|
|
|
|
buildAutomationScheduleDashboard,
|
|
|
|
@@ -1809,6 +1815,12 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
const avatarDecorationExportJsonHeal = await this._healAvatarDecorationExportCursorOnPartition(gid).catch(() => ({
|
|
|
|
|
relisted: 0
|
|
|
|
|
}))
|
|
|
|
|
const deviceSyncJsonHeal = await this._healDeviceSyncExportCursorOnPartition(gid).catch(() => ({
|
|
|
|
|
relisted: 0
|
|
|
|
|
}))
|
|
|
|
|
const discoveryListingExportJsonHeal = await this._healDiscoveryListingExportCursorOnPartition(gid).catch(() => ({
|
|
|
|
|
relisted: 0
|
|
|
|
|
}))
|
|
|
|
|
return {
|
|
|
|
|
voiceApplied,
|
|
|
|
|
emojiSlots,
|
|
|
|
@@ -1871,7 +1883,9 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
inviteLinkJsonHeal,
|
|
|
|
|
vanityUrlJsonHeal,
|
|
|
|
|
sessionActivityJsonHeal,
|
|
|
|
|
avatarDecorationExportJsonHeal
|
|
|
|
|
avatarDecorationExportJsonHeal,
|
|
|
|
|
deviceSyncJsonHeal,
|
|
|
|
|
discoveryListingExportJsonHeal
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -11210,6 +11224,12 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
guildInstance.on('avatar-decoration-export-json-sync', (payload) => {
|
|
|
|
|
this._onAvatarDecorationExportJsonGossip(payload).catch(() => {})
|
|
|
|
|
})
|
|
|
|
|
guildInstance.on('device-sync-json-sync', (payload) => {
|
|
|
|
|
this._onDeviceSyncJsonGossip(payload).catch(() => {})
|
|
|
|
|
})
|
|
|
|
|
guildInstance.on('discovery-listing-export-json-sync', (payload) => {
|
|
|
|
|
this._onDiscoveryListingExportJsonGossip(payload).catch(() => {})
|
|
|
|
|
})
|
|
|
|
|
guildInstance.on('message-search-request', (payload) => {
|
|
|
|
|
this._onMessageSearchRequestGossip(payload).catch(() => {})
|
|
|
|
|
})
|
|
|
|
@@ -26862,6 +26882,188 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
return row
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _deviceJsonRegistryEntries () {
|
|
|
|
|
if (!this.guild?.guild) return []
|
|
|
|
|
const entries = []
|
|
|
|
|
if (this.deviceSync) {
|
|
|
|
|
const devices = await this.deviceSync.listDevices().catch(() => [])
|
|
|
|
|
for (const d of devices.slice(0, 32)) {
|
|
|
|
|
entries.push({
|
|
|
|
|
deviceId: d.id,
|
|
|
|
|
label: d.label || 'Device',
|
|
|
|
|
platform: d.isPrimary ? 'primary' : 'paired',
|
|
|
|
|
lastSeenAt: d.lastSeenAt || 0,
|
|
|
|
|
exportedAt: Date.now()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!entries.length) {
|
|
|
|
|
entries.push({
|
|
|
|
|
deviceId: 'local',
|
|
|
|
|
label: 'This device',
|
|
|
|
|
platform: 'desktop',
|
|
|
|
|
lastSeenAt: Date.now(),
|
|
|
|
|
exportedAt: Date.now()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return entries
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _discoveryListingJsonRegistryEntries () {
|
|
|
|
|
if (!this.guild?.guild || !this.discovery) return []
|
|
|
|
|
const gid = this.guild.guild.id
|
|
|
|
|
const listings = await this.discovery.listPublicListings({ prune: false }).catch(() => [])
|
|
|
|
|
const entries = listings
|
|
|
|
|
.filter((r) => r.guildId === gid)
|
|
|
|
|
.slice(0, 32)
|
|
|
|
|
.map((r) => ({
|
|
|
|
|
guildId: r.guildId,
|
|
|
|
|
name: r.name || '',
|
|
|
|
|
publicListing: !!r.publicListing,
|
|
|
|
|
memberCount: r.memberCount || 0,
|
|
|
|
|
tags: (r.tags || []).slice(0, 8),
|
|
|
|
|
exportedAt: r.updatedAt || r.createdAt || Date.now()
|
|
|
|
|
}))
|
|
|
|
|
if (!entries.length) {
|
|
|
|
|
entries.push({
|
|
|
|
|
guildId: gid,
|
|
|
|
|
name: this.guild.guild.name || 'Guild',
|
|
|
|
|
publicListing: !!this.guild.guild.publicListing,
|
|
|
|
|
memberCount: 0,
|
|
|
|
|
tags: [],
|
|
|
|
|
exportedAt: Date.now()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return entries
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getDeviceSyncJsonExport () {
|
|
|
|
|
const gid = this.guild?.guild?.id || null
|
|
|
|
|
const span = this.log.time('device.json', { spanKind: 'device.json', guildId: gid, context: 'read' })
|
|
|
|
|
try {
|
|
|
|
|
if (!this.guild?.guild) { span.end({ guildDeviceJsonCount: 0, skipped: true }); return null }
|
|
|
|
|
await this._initDeliveryReceipts(this.guild.guild.id)
|
|
|
|
|
const row = await this.deliveryReceipts.getDeviceSyncJsonExport()
|
|
|
|
|
if (!row?.signature) {
|
|
|
|
|
span.end({ guildDeviceJsonCount: row ? 1 : 0, hasSignature: false, bridgeKind: 'device.json' })
|
|
|
|
|
return row
|
|
|
|
|
}
|
|
|
|
|
const verified = verifyDeviceSyncJson(exportBodyFromSlice(row) || row.jsonBody, row.signature, { guildId: this.guild.guild.id, relaySecret: this.guild.guild.id })
|
|
|
|
|
const out = { ...row, signatureValid: verified.ok, deviceCount: row.deviceCount || 0 }
|
|
|
|
|
span.end({ guildDeviceJsonCount: 1, hasSignature: true, signatureValid: verified.ok, bridgeKind: 'device.json' })
|
|
|
|
|
return out
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.log.error('device.json error', { guildId: gid, context: 'read', error: err?.message || String(err) })
|
|
|
|
|
span.fail(err); throw err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async exportDeviceSyncJson (opts = {}) {
|
|
|
|
|
if (!this.guild?.guild) throw new Error('no guild')
|
|
|
|
|
await this._initDeliveryReceipts(this.guild.guild.id)
|
|
|
|
|
const entries = await this._deviceJsonRegistryEntries()
|
|
|
|
|
const jsonBody = buildDeviceSyncJsonBody(entries)
|
|
|
|
|
const signed = signDeviceSyncJson(jsonBody, { guildId: this.guild.guild.id, relaySecret: this.guild.guild.id })
|
|
|
|
|
const exportedAt = Date.now()
|
|
|
|
|
if (opts.recordMesh !== false) {
|
|
|
|
|
await this.deliveryReceipts.recordDeviceSyncJsonExport({ jsonBody: signed.jsonBody || signed.json, signature: signed.signature, signatureAlg: signed.signatureAlg, exportedAt, deviceCount: entries.length })
|
|
|
|
|
}
|
|
|
|
|
return { format: 'json', body: signed.json, signature: signed.signature, signatureAlg: signed.signatureAlg, exportedAt, deviceCount: entries.length }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async pushDeviceSyncJsonToMesh () {
|
|
|
|
|
const gid = this.guild?.guild?.id || null
|
|
|
|
|
const span = this.log.time('device.json', { spanKind: 'device.json', guildId: gid, context: 'mesh.push' })
|
|
|
|
|
try {
|
|
|
|
|
if (!this.guild?.guild) throw new Error('no guild')
|
|
|
|
|
if (!(await this._hasPerm(PERMISSION.MANAGE_GUILD))) throw new Error('no permission to sync device JSON')
|
|
|
|
|
const exported = await this.exportDeviceSyncJson({ recordMesh: false })
|
|
|
|
|
if (!exported.signature) throw new Error('device sync json export not signed')
|
|
|
|
|
const payload = { guildId: this.guild.guild.id, exportedAt: exported.exportedAt || Date.now(), exportedBy: this.identity.user?.id || null, jsonBody: exported.body, signature: exported.signature, signatureAlg: exported.signatureAlg, deviceCount: exported.deviceCount || 0 }
|
|
|
|
|
if (this.guild.gossipDeviceSyncJsonSync) this.guild.gossipDeviceSyncJsonSync(payload)
|
|
|
|
|
this.emit('device-sync-json-sync', payload)
|
|
|
|
|
await this.deliveryReceipts.recordDeviceSyncJsonExport({ jsonBody: exported.body, signature: exported.signature, signatureAlg: exported.signatureAlg, exportedAt: exported.exportedAt, deviceCount: exported.deviceCount })
|
|
|
|
|
span.end({ guildDeviceJsonCount: exported.deviceCount || 1, meshPushed: true, bridgeKind: 'device.json' })
|
|
|
|
|
return exported
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.log.error('device.json error', { guildId: gid, context: 'mesh.push', error: err?.message || String(err) })
|
|
|
|
|
span.fail(err); throw err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async clearDeviceSyncJsonExports () {
|
|
|
|
|
if (!this.guild?.guild) throw new Error('no guild')
|
|
|
|
|
if (!(await this._hasPerm(PERMISSION.MANAGE_GUILD))) throw new Error('no permission to clear device sync JSON exports')
|
|
|
|
|
await this._initDeliveryReceipts(this.guild.guild.id)
|
|
|
|
|
const removed = await this.deliveryReceipts.clearDeviceSyncJsonExports()
|
|
|
|
|
this.emit('device-sync-json-cleared', { removed })
|
|
|
|
|
return { removed }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getLastDiscoveryListingExport () {
|
|
|
|
|
if (!this.guild?.guild) return null
|
|
|
|
|
const snap = this._lastDiscoveryListingExport
|
|
|
|
|
if (snap?.guildId === this.guild.guild.id) return snap
|
|
|
|
|
return { guildId: this.guild.guild.id, exportedAt: Date.now(), listingCount: 0, signed: false, meshPushed: false }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async exportDiscoveryListingMesh (opts = {}) {
|
|
|
|
|
if (!this.guild?.guild) throw new Error('no guild')
|
|
|
|
|
const roles = await this._memberRoles()
|
|
|
|
|
if (!roleHasPermission(roles, PERMISSION.MANAGE_GUILD)) throw new Error('no permission to export discovery listing mesh')
|
|
|
|
|
const entries = await this._discoveryListingJsonRegistryEntries()
|
|
|
|
|
const jsonBody = buildDiscoveryListingExportJsonBody(entries)
|
|
|
|
|
const signed = signDiscoveryListingExportJson(jsonBody, { guildId: this.guild.guild.id, relaySecret: this.guild.guild.id })
|
|
|
|
|
const exportedAt = Date.now()
|
|
|
|
|
const meta = { guildId: this.guild.guild.id, exportedAt, listingCount: entries.length, signed: !!signed.signature, meshPushed: false }
|
|
|
|
|
this._lastDiscoveryListingExport = meta
|
|
|
|
|
if (opts.recordMesh !== false) {
|
|
|
|
|
await this.deliveryReceipts.recordDiscoveryListingExportJson({ jsonBody: signed.jsonBody || signed.json, signature: signed.signature, signatureAlg: signed.signatureAlg, exportedAt, listingCount: entries.length })
|
|
|
|
|
}
|
|
|
|
|
return { format: 'json', body: signed.json, signature: signed.signature, signatureAlg: signed.signatureAlg, exportedAt, listingCount: entries.length, meta }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async pushDiscoveryListingExportToMesh () {
|
|
|
|
|
const gid = this.guild?.guild?.id || null
|
|
|
|
|
const span = this.log.time('discovery.json', { spanKind: 'discovery.json', guildId: gid, context: 'mesh.push' })
|
|
|
|
|
try {
|
|
|
|
|
const exported = await this.exportDiscoveryListingMesh({ recordMesh: false })
|
|
|
|
|
if (!exported.signature) throw new Error('discovery listing export json not signed')
|
|
|
|
|
const payload = { guildId: this.guild.guild.id, exportedAt: exported.exportedAt || Date.now(), exportedBy: this.identity.user?.id || null, jsonBody: exported.body, signature: exported.signature, signatureAlg: exported.signatureAlg, listingCount: exported.listingCount || 0 }
|
|
|
|
|
if (this.guild.gossipDiscoveryListingExportJsonSync) this.guild.gossipDiscoveryListingExportJsonSync(payload)
|
|
|
|
|
this.emit('discovery-listing-export-json-sync', payload)
|
|
|
|
|
await this.deliveryReceipts.recordDiscoveryListingExportJson({ jsonBody: exported.body, signature: exported.signature, signatureAlg: exported.signatureAlg, exportedAt: exported.exportedAt, listingCount: exported.listingCount })
|
|
|
|
|
this._lastDiscoveryListingExport = { ...exported.meta, meshPushed: true }
|
|
|
|
|
span.end({ guildDiscoveryJsonCount: exported.listingCount || 0, meshPushed: true, bridgeKind: 'discovery.json' })
|
|
|
|
|
return exported
|
|
|
|
|
} catch (err) {
|
|
|
|
|
this.log.error('discovery.json error', { guildId: gid, context: 'mesh.push', error: err?.message || String(err) })
|
|
|
|
|
span.fail(err); throw err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _onDeviceSyncJsonGossip (payload) {
|
|
|
|
|
if (!payload?.guildId || !payload?.jsonBody || !payload?.signature) return null
|
|
|
|
|
if (this.guild?.guild?.id !== payload.guildId) return null
|
|
|
|
|
await this._initDeliveryReceipts(payload.guildId)
|
|
|
|
|
this._shouldGossipDeviceSyncRegistryJson(payload)
|
|
|
|
|
const row = await this.deliveryReceipts.ingestDeviceSyncJsonSlice(payload.guildId, payload)
|
|
|
|
|
if (row?.duplicate) this._deviceSyncJsonDuplicateAt = row.exportedAt || payload.exportedAt || null
|
|
|
|
|
if (row) this.emit('device-sync-json-sync', payload)
|
|
|
|
|
return row
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async _onDiscoveryListingExportJsonGossip (payload) {
|
|
|
|
|
if (!payload?.guildId || !payload?.jsonBody || !payload?.signature) return null
|
|
|
|
|
if (this.guild?.guild?.id !== payload.guildId) return null
|
|
|
|
|
await this._initDeliveryReceipts(payload.guildId)
|
|
|
|
|
this._shouldGossipDiscoveryListingExportJson(payload)
|
|
|
|
|
const row = await this.deliveryReceipts.ingestDiscoveryListingExportJsonSlice(payload.guildId, payload)
|
|
|
|
|
if (row?.duplicate) this._discoveryListingExportJsonDuplicateAt = row.exportedAt || payload.exportedAt || null
|
|
|
|
|
if (row) this.emit('discovery-listing-export-json-sync', payload)
|
|
|
|
|
return row
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async getAuditExportSchedule () {
|
|
|
|
|
if (!this.guild?.guild) {
|
|
|
|
@@ -31803,6 +32005,12 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
let avatarDecorationExportJsonRows = []
|
|
|
|
|
let lastAvatarDecorationExport = null
|
|
|
|
|
let guildSessionActivities = []
|
|
|
|
|
let deviceSyncJsonMeta = null
|
|
|
|
|
let deviceSyncJsonRows = []
|
|
|
|
|
let discoveryListingExportJsonRows = []
|
|
|
|
|
let lastDiscoveryListingExport = null
|
|
|
|
|
let guildPairedDevices = []
|
|
|
|
|
let guildDiscoveryListings = []
|
|
|
|
|
let lastComplianceSnapshot = null
|
|
|
|
|
let lastArchivePeerExport = null
|
|
|
|
|
let automationScheduleDashboard = null
|
|
|
|
@@ -32073,6 +32281,35 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
createdAt: c.createdAt || null,
|
|
|
|
|
updatedAt: c.updatedAt || Date.now()
|
|
|
|
|
}))
|
|
|
|
|
deviceSyncJsonMeta = await this.getDeviceSyncJsonExport().catch(() => null)
|
|
|
|
|
deviceSyncJsonRows = (await this.deliveryReceipts.listDeviceSyncJsonExports(32)).map((row) => {
|
|
|
|
|
if (!row?.signature || !guild?.id) return row
|
|
|
|
|
const verified = verifyDeviceSyncJson(exportBodyFromSlice(row) || row.jsonBody, row.signature, { guildId: guild.id, relaySecret: guild.id })
|
|
|
|
|
return { ...row, signatureValid: verified.ok }
|
|
|
|
|
})
|
|
|
|
|
discoveryListingExportJsonRows = (await this.deliveryReceipts.listDiscoveryListingExportJsonExports(32)).map((row) => {
|
|
|
|
|
if (!row?.signature || !guild?.id) return row
|
|
|
|
|
const verified = verifyDiscoveryListingExportJson(exportBodyFromSlice(row) || row.jsonBody, row.signature, { guildId: guild.id, relaySecret: guild.id })
|
|
|
|
|
return { ...row, signatureValid: verified.ok }
|
|
|
|
|
})
|
|
|
|
|
lastDiscoveryListingExport = await this.getLastDiscoveryListingExport()
|
|
|
|
|
if (this.deviceSync) {
|
|
|
|
|
guildPairedDevices = (await this.deviceSync.listDevices().catch(() => [])).slice(0, 16).map((d) => ({
|
|
|
|
|
id: d.id,
|
|
|
|
|
name: d.label || 'Device',
|
|
|
|
|
role: d.isPrimary ? 'primary' : 'paired',
|
|
|
|
|
updatedAt: d.lastSeenAt || Date.now()
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
if (this.discovery) {
|
|
|
|
|
const listings = await this.discovery.listPublicListings({ prune: false }).catch(() => [])
|
|
|
|
|
guildDiscoveryListings = listings.filter((r) => r.guildId === guild.id).slice(0, 16).map((r) => ({
|
|
|
|
|
id: r.id || r.guildId,
|
|
|
|
|
name: r.name || '',
|
|
|
|
|
role: r.publicListing ? 'public' : 'private',
|
|
|
|
|
updatedAt: r.updatedAt || r.createdAt || Date.now()
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const auditLogFilterOptions = [
|
|
|
|
|
{ id: 'all', label: 'All' },
|
|
|
|
@@ -32422,6 +32659,10 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
this._sessionActivityJsonDuplicateAt = null
|
|
|
|
|
const avatarDecorationExportJsonDuplicateAt = this._avatarDecorationExportJsonDuplicateAt || null
|
|
|
|
|
this._avatarDecorationExportJsonDuplicateAt = null
|
|
|
|
|
const deviceSyncJsonDuplicateAt = this._deviceSyncJsonDuplicateAt || null
|
|
|
|
|
this._deviceSyncJsonDuplicateAt = null
|
|
|
|
|
const discoveryListingExportJsonDuplicateAt = this._discoveryListingExportJsonDuplicateAt || null
|
|
|
|
|
this._discoveryListingExportJsonDuplicateAt = null
|
|
|
|
|
return {
|
|
|
|
|
onboarded: this.onboarded,
|
|
|
|
|
sessionReady: this._sessionReady,
|
|
|
|
@@ -32597,6 +32838,8 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
profileBannerExportJsonDuplicateAt,
|
|
|
|
|
sessionActivityJsonDuplicateAt,
|
|
|
|
|
avatarDecorationExportJsonDuplicateAt,
|
|
|
|
|
deviceSyncJsonDuplicateAt,
|
|
|
|
|
discoveryListingExportJsonDuplicateAt,
|
|
|
|
|
digestRelayHandoffJsonMeta,
|
|
|
|
|
digestRelayHandoffJsonRows,
|
|
|
|
|
archivePeerExportJsonRows,
|
|
|
|
@@ -32727,6 +32970,16 @@ class PearcordPlatform extends EventEmitter {
|
|
|
|
|
guildSessionActivities,
|
|
|
|
|
guildSessionJsonCount:
|
|
|
|
|
(sessionActivityJsonRows || []).length + (guildSessionActivities || []).length,
|
|
|
|
|
deviceSyncJsonMeta,
|
|
|
|
|
deviceSyncJsonRows,
|
|
|
|
|
discoveryListingExportJsonRows,
|
|
|
|
|
lastDiscoveryListingExport,
|
|
|
|
|
guildPairedDevices,
|
|
|
|
|
guildDiscoveryListings,
|
|
|
|
|
guildDeviceJsonCount:
|
|
|
|
|
(deviceSyncJsonRows || []).length + (guildPairedDevices || []).length,
|
|
|
|
|
guildDiscoveryJsonCount:
|
|
|
|
|
(discoveryListingExportJsonRows || []).length + (guildDiscoveryListings || []).length,
|
|
|
|
|
automationScheduleDashboard,
|
|
|
|
|
automationHealthDashboard,
|
|
|
|
|
automationDigestNotifyPrefs,
|
|
|
|
@@ -33350,6 +33603,8 @@ const { notificationJsonMixin } = require('./notification-json-mixin')
|
|
|
|
|
const { statusJsonMixin } = require('./status-json-mixin')
|
|
|
|
|
const { activityJsonMixin } = require('./activity-json-mixin')
|
|
|
|
|
const { sessionJsonMixin } = require('./session-json-mixin')
|
|
|
|
|
const { deviceJsonMixin } = require('./device-json-mixin')
|
|
|
|
|
const { discoveryJsonMixin } = require('./discovery-json-mixin')
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, pollSchedulingMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, notificationsActivityMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, userSettingsMixin)
|
|
|
|
@@ -33389,3 +33644,5 @@ Object.assign(PearcordPlatform.prototype, notificationJsonMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, statusJsonMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, activityJsonMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, sessionJsonMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, deviceJsonMixin)
|
|
|
|
|
Object.assign(PearcordPlatform.prototype, discoveryJsonMixin)
|
|
|
|
|