Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 3 additions & 10 deletions scripts/product-proof-network-policy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1867,23 +1867,16 @@ function realtimeTopic(topic, subscriptions, { minJoins = 1, maxJoins = 1 } = {}
}

function routeRealtimeTopics(routeDefinition, options) {
const { conversationIdentity, viewportLabel, workspaceIdentity } = options;
const { conversationIdentity, workspaceIdentity } = options;
const topics = [
// This persistent app-scope topic also owns email-import status invalidation. Route-level
// status consumers must not create a second channel for the same workspace-bound tables.
realtimeTopic(
`realtime:workspace-live-invalidation-${workspaceIdentity}`,
workspaceSubscriptions.map(([event, table]) => subscription(event, table, workspaceIdentity)),
),
];

if (viewportLabel === 'desktop-1440x900' && desktopSidebarRoutes.has(routeDefinition.label)) {
topics.push(
realtimeTopic(`realtime:email-import-status-${workspaceIdentity}`, [
subscription('*', 'email_provider_configs', workspaceIdentity),
subscription('*', 'email_import_progress', workspaceIdentity),
]),
);
}

// Home mounts DraftMessages only when the independently preflighted mailbox count is non-zero.
// The fixture is expected to be empty, but this exact source-owned optional join makes any
// unexpected non-empty state observable without permitting an unknown topic.
Expand Down
81 changes: 51 additions & 30 deletions scripts/product-proof-network-policy.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1610,40 +1610,61 @@ test('route-specific Realtime is exact and tenant denial never joins conversatio
);
});

test('desktop email import Realtime remains one exact workspace-bound join', () => {
test('email import Realtime is owned only by the persistent workspace invalidation topic', () => {
const factory = createProductProofNetworkPolicyFactory({ assetManifest: manifest() });
const expected = {
maxJoins: 1,
minJoins: 1,
subscriptions: [
{
event: '*',
filter: `workspace_id=eq.${workspaceIdentity}`,
schema: 'public',
table: 'email_provider_configs',
},
{
event: '*',
filter: `workspace_id=eq.${workspaceIdentity}`,
schema: 'public',
table: 'email_import_progress',
},
],
topic: `realtime:email-import-status-${workspaceIdentity}`,
};

for (const routeLabel of ['home', 'reviews']) {
const policy = factory(routeOptions(routeLabel));
assert.deepEqual(
policy.realtime.topics.filter(({ topic }) => topic.includes('email-import-status')),
[expected],
);
for (const viewportLabel of ['desktop-1440x900', 'mobile-390x844']) {
for (const routeLabel of ['home', 'reviews']) {
const policy = factory(routeOptions(routeLabel, { viewportLabel }));
assert.equal(
policy.realtime.topics.some(({ topic }) => topic.includes('email-import-status')),
false,
);
const workspaceTopic = policy.realtime.topics.find(
({ topic }) => topic === `realtime:workspace-live-invalidation-${workspaceIdentity}`,
);
assert.deepEqual(
workspaceTopic.subscriptions.filter(({ table }) =>
['email_provider_configs', 'email_import_progress'].includes(table),
),
[
{
event: '*',
filter: `workspace_id=eq.${workspaceIdentity}`,
schema: 'public',
table: 'email_provider_configs',
},
{
event: '*',
filter: `workspace_id=eq.${workspaceIdentity}`,
schema: 'public',
table: 'email_import_progress',
},
],
);
}
}

const mobile = factory(routeOptions('home', { viewportLabel: 'mobile-390x844' }));
const statusSource = readFileSync(
new URL('../src/hooks/useEmailImportStatus.tsx', import.meta.url),
'utf8',
);
assert.equal(statusSource.includes('.channel('), false);
assert.equal(statusSource.includes('removeChannel('), false);

const invalidationSource = readFileSync(
new URL('../src/hooks/useWorkspaceLiveInvalidation.ts', import.meta.url),
'utf8',
);
assert.equal(
mobile.realtime.topics.some(({ topic }) => topic.includes('email-import-status')),
false,
invalidationSource.split(".channel(`workspace-live-invalidation-${workspaceId}`)").length - 1,
1,
);
for (const table of ['email_provider_configs', 'email_import_progress']) {
assert.equal(invalidationSource.split(`table: '${table}'`).length - 1, 1, table);
}
assert.equal(
invalidationSource.split("['email-import-status', workspaceId]").length - 1,
1,
);
});

Expand Down
Loading