mirror of
https://github.com/hanzoai/social.git
synced 2026-10-27 09:19:48 +00:00
* Say when a connector catalog is loading, missing, or unconfigured. The Connect card treated a /v1/provider read that had not answered as "not in the catalog". Cards now say whether that read is in flight, failed, the network is absent, or present without app credentials — and name the connect-plane variables, keeping the publish plane's names when they differ. The read asks for each social network by id instead of the unfiltered registry. Co-authored-by: z <[email protected]> * Let an organization keep several accounts on one network. Connect already listed every handle the social API returned, but it never said which was a person and which was the company. Each account can now be personal or the network's own business kind — company on X, a Company Page on LinkedIn, a Page on Facebook, Business on Instagram — and the composer counts those kinds. The kind is stored on /v1/settings/social-audiences so it does not share a document with the Postiz post settings. Co-authored-by: z <[email protected]> * Add a Keys page for an organization's own app credentials. GET and PUT /v1/social/credentials are the contract the connect plane is growing: the public client id comes back, the secret never does, an omitted secret is left sealed, and an empty secret clears it. The screen masks both. A deployment that answers 404 or 501 has not shipped the route, and Keys stays off the rail until it has. Co-authored-by: z <[email protected]> --------- Co-authored-by: Cursor Agent <[email protected]> Co-authored-by: z <[email protected]>
73 lines
2.2 KiB
JavaScript
73 lines
2.2 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
|
|
import {
|
|
accountLine,
|
|
audienceLabel,
|
|
audiencesFor,
|
|
readAudiences,
|
|
whereLine,
|
|
writeAudiences,
|
|
} from '../src/audience.ts'
|
|
|
|
test('each network names personal and its own kind of business account', () => {
|
|
assert.deepEqual(
|
|
audiencesFor('x').map((choice) => choice.label),
|
|
['Personal', 'Company'],
|
|
)
|
|
assert.deepEqual(
|
|
audiencesFor('linkedin').map((choice) => choice.label),
|
|
['Personal', 'Company Page'],
|
|
)
|
|
assert.deepEqual(
|
|
audiencesFor('facebook').map((choice) => choice.label),
|
|
['Personal', 'Page'],
|
|
)
|
|
assert.deepEqual(
|
|
audiencesFor('instagram').map((choice) => choice.label),
|
|
['Personal', 'Business'],
|
|
)
|
|
assert.equal(audienceLabel('tiktok', 'business'), 'Business')
|
|
assert.equal(audienceLabel('x', undefined), '')
|
|
})
|
|
|
|
test('a kind map ignores anything that is not personal or business', () => {
|
|
assert.deepEqual(
|
|
readAudiences({
|
|
accounts: { a: 'personal', b: 'business', c: 'page', d: '', e: 1 },
|
|
posts: { keep: true },
|
|
}),
|
|
{ a: 'personal', b: 'business' },
|
|
)
|
|
assert.deepEqual(readAudiences(null), {})
|
|
assert.deepEqual(readAudiences({ accounts: ['personal'] }), {})
|
|
})
|
|
|
|
test('writing kinds keeps every other settings key', () => {
|
|
const next = writeAudiences(
|
|
{ posts: { p1: { tone: 'plain' } }, accounts: { old: 'personal' } },
|
|
{ acct_x: 'business' },
|
|
)
|
|
assert.deepEqual(next.posts, { p1: { tone: 'plain' } })
|
|
assert.deepEqual(next.accounts, { acct_x: 'business' })
|
|
assert.deepEqual(writeAudiences(undefined, { a: 'personal' }).accounts, { a: 'personal' })
|
|
})
|
|
|
|
test('several accounts on one network are counted and their kinds named once', () => {
|
|
const audiences = { personal: 'personal', company: 'business', bare: 'personal' }
|
|
assert.equal(
|
|
whereLine(
|
|
'linkedin',
|
|
[{ id: 'personal' }, { id: 'company' }, { id: 'bare' }],
|
|
audiences,
|
|
),
|
|
'Where posts go — 3 accounts · Personal, Company Page',
|
|
)
|
|
assert.equal(accountLine(1, ['Personal']), '1 account · Personal')
|
|
assert.equal(accountLine(0, []), '0 accounts')
|
|
assert.equal(
|
|
whereLine('x', [{ id: 'missing' }], {}),
|
|
'Where posts go — 1 account',
|
|
)
|
|
})
|