openvibers/openvibe.network Commits
Expire approved-unused confirmations on cancel and drop Trade Events…
Changes
@@@ -40,8 +40,8 @@ const LIVE = "(state = 'pending' OR (state = 'approved' AND used_at IS NULL))";const fail = (status, code, detail) => { throw new store.DevError(status, code, detail); };const nowIso = () => new Date().toISOString();--/** The state a read reports: a pending row past expires_at is expired before the sweep records it. */--const stateOf = (c, now = nowIso()) => (c.state === 'pending' && c.expires_at <= now ? 'expired' : c.state);++/** The state a read reports: a live row past expires_at (pending, or approved and unused) is expired before the sweep records it. */++const stateOf = (c, now = nowIso()) => ((c.state === 'pending' || (c.state === 'approved' && !c.used_at)) && c.expires_at <= now ? 'expired' : c.state);/** network.confirmation-request@1: owner and requested_by rebuilt as SubjectRefs, details/resources parsed. */function confirmationView(c) {@@@ -186,9 +186,9 @@ async function read(db, { id, audience }) {}/**-- * The owning service withdraws one it created: a pending or approved-unused row becomes cancelled (reason `service`);-- * one already cancelled is returned as it is; a used, denied or expired one is 409 confirmation.not_pending. The-- * owner's standing rules are left alone. → { confirmation }++ * The owning service withdraws one it created: a pending or approved-unused row still inside its ttl becomes cancelled++ * (reason `service`); one already cancelled is returned as it is; a used, denied or expired (past `expires_at`) one is++ * 409 confirmation.not_pending. The owner's standing rules are left alone. → { confirmation }*/async function cancel(db, { id, audience }, { ctx } = {}) {await db.tx(async () => {@@@ -130,8 +130,6 @@ const DEFAULT_GRANTS = [['trade', 'events.event.publish', 'openvibe.events', []],['trade', 'sources.item.read', 'openvibe.sources', []],['trade', 'sources.source.read', 'openvibe.sources', []],-- // Trade subscribes to the Sources filings it follows (plan T9 step 1), as Coupons and Deals do.-- ['trade', 'events.subscription.manage', 'openvibe.events', []],// Wave 18: Deals and Coupons; Wave 21 Stage B: the Host API publishes deploy/domain events.['deals', 'identity.subject.resolve', SELF_AUDIENCE, []],['deals', 'events.event.publish', 'openvibe.events', []],@@@ -399,6 +399,7 @@ for (const [id, name] of PEOPLE) T[name] = jwt.sign({ sub: id, id }, keys.privatawait approve(i2);await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i2.id);refused(await internal('media', 'POST', `/${i2.id}/consume`, { request_digest: D }), 409, 'confirmation.expired');++ refused(await internal('media', 'POST', `/${i2.id}/cancel`, {}), 409, 'confirmation.not_pending');const i3 = ok(await internal('media', 'POST', '', askBody()), 201).confirmation;await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i3.id);refused(await internal('media', 'POST', `/${i3.id}/cancel`, {}), 409, 'confirmation.not_pending');@@@ -167,11 +167,6 @@ const server = http.createServer(app);const cps = await token({ client_id: 'coupons', client_secret: 'coupons-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });assert.strictEqual(cps.status, 200, JSON.stringify(cps.body));assert.strictEqual(cps.body.scope, 'events.subscription.manage', 'Coupons manages its Events subscriptions');-- // Trade subscribes to the Sources filings it follows (plan T9 step 1).-- await db.prepare("UPDATE oauth_clients SET client_secret = 'trade-secret' WHERE client_id = 'trade'").run();-- const trs = await token({ client_id: 'trade', client_secret: 'trade-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });-- assert.strictEqual(trs.status, 200, JSON.stringify(trs.body));-- assert.strictEqual(trs.body.scope, 'events.subscription.manage', 'Trade manages its Events subscriptions');// Go-live fan-out accepts Live's token (network.notifications.push); a narrower token is refused.r = await post('/internal/events/stream-live', {}, { authorization: `Bearer ${full}` });
@@ -40,8 +40,8 @@ const LIVE = "(state = 'pending' OR (state = 'approved' AND used_at IS NULL))";
@@ -40,8 +40,8 @@ const LIVE = "(state = 'pending' OR (state = 'approved' AND used_at IS NULL))";
const fail = (status, code, detail) => { throw new store.DevError(status, code, detail); };
const fail = (status, code, detail) => { throw new store.DevError(status, code, detail); };
const nowIso = () => new Date().toISOString();
const nowIso = () => new Date().toISOString();
-/** The state a read reports: a pending row past expires_at is expired before the sweep records it. */
-const stateOf = (c, now = nowIso()) => (c.state === 'pending' && c.expires_at <= now ? 'expired' : c.state);
+/** The state a read reports: a live row past expires_at (pending, or approved and unused) is expired before the sweep records it. */
+const stateOf = (c, now = nowIso()) => ((c.state === 'pending' || (c.state === 'approved' && !c.used_at)) && c.expires_at <= now ? 'expired' : c.state);
/** network.confirmation-request@1: owner and requested_by rebuilt as SubjectRefs, details/resources parsed. */
/** network.confirmation-request@1: owner and requested_by rebuilt as SubjectRefs, details/resources parsed. */
function confirmationView(c) {
function confirmationView(c) {
@@ -186,9 +186,9 @@ async function read(db, { id, audience }) {
@@ -186,9 +186,9 @@ async function read(db, { id, audience }) {
}
}
/**
/**
- * The owning service withdraws one it created: a pending or approved-unused row becomes cancelled (reason `service`);
- * one already cancelled is returned as it is; a used, denied or expired one is 409 confirmation.not_pending. The
- * owner's standing rules are left alone. → { confirmation }
+ * The owning service withdraws one it created: a pending or approved-unused row still inside its ttl becomes cancelled
+ * (reason `service`); one already cancelled is returned as it is; a used, denied or expired (past `expires_at`) one is
+ * 409 confirmation.not_pending. The owner's standing rules are left alone. → { confirmation }
*/
*/
async function cancel(db, { id, audience }, { ctx } = {}) {
async function cancel(db, { id, audience }, { ctx } = {}) {
await db.tx(async () => {
await db.tx(async () => {
@@ -130,8 +130,6 @@ const DEFAULT_GRANTS = [
@@ -130,8 +130,6 @@ const DEFAULT_GRANTS = [
['trade', 'events.event.publish', 'openvibe.events', []],
['trade', 'events.event.publish', 'openvibe.events', []],
['trade', 'sources.item.read', 'openvibe.sources', []],
['trade', 'sources.item.read', 'openvibe.sources', []],
['trade', 'sources.source.read', 'openvibe.sources', []],
['trade', 'sources.source.read', 'openvibe.sources', []],
- // Trade subscribes to the Sources filings it follows (plan T9 step 1), as Coupons and Deals do.
- ['trade', 'events.subscription.manage', 'openvibe.events', []],
// Wave 18: Deals and Coupons; Wave 21 Stage B: the Host API publishes deploy/domain events.
// Wave 18: Deals and Coupons; Wave 21 Stage B: the Host API publishes deploy/domain events.
['deals', 'identity.subject.resolve', SELF_AUDIENCE, []],
['deals', 'identity.subject.resolve', SELF_AUDIENCE, []],
['deals', 'events.event.publish', 'openvibe.events', []],
['deals', 'events.event.publish', 'openvibe.events', []],
@@ -399,6 +399,7 @@ for (const [id, name] of PEOPLE) T[name] = jwt.sign({ sub: id, id }, keys.privat
@@ -399,6 +399,7 @@ for (const [id, name] of PEOPLE) T[name] = jwt.sign({ sub: id, id }, keys.privat
await approve(i2);
await approve(i2);
await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i2.id);
await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i2.id);
refused(await internal('media', 'POST', `/${i2.id}/consume`, { request_digest: D }), 409, 'confirmation.expired');
refused(await internal('media', 'POST', `/${i2.id}/consume`, { request_digest: D }), 409, 'confirmation.expired');
+ refused(await internal('media', 'POST', `/${i2.id}/cancel`, {}), 409, 'confirmation.not_pending');
const i3 = ok(await internal('media', 'POST', '', askBody()), 201).confirmation;
const i3 = ok(await internal('media', 'POST', '', askBody()), 201).confirmation;
await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i3.id);
await db.prepare("UPDATE dev_confirmations SET expires_at = '2001-01-01T00:00:00.000Z' WHERE id = ?").run(i3.id);
refused(await internal('media', 'POST', `/${i3.id}/cancel`, {}), 409, 'confirmation.not_pending');
refused(await internal('media', 'POST', `/${i3.id}/cancel`, {}), 409, 'confirmation.not_pending');
@@ -167,11 +167,6 @@ const server = http.createServer(app);
@@ -167,11 +167,6 @@ const server = http.createServer(app);
const cps = await token({ client_id: 'coupons', client_secret: 'coupons-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });
const cps = await token({ client_id: 'coupons', client_secret: 'coupons-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });
assert.strictEqual(cps.status, 200, JSON.stringify(cps.body));
assert.strictEqual(cps.status, 200, JSON.stringify(cps.body));
assert.strictEqual(cps.body.scope, 'events.subscription.manage', 'Coupons manages its Events subscriptions');
assert.strictEqual(cps.body.scope, 'events.subscription.manage', 'Coupons manages its Events subscriptions');
- // Trade subscribes to the Sources filings it follows (plan T9 step 1).
- await db.prepare("UPDATE oauth_clients SET client_secret = 'trade-secret' WHERE client_id = 'trade'").run();
- const trs = await token({ client_id: 'trade', client_secret: 'trade-secret', audience: 'openvibe.events', scope: 'events.subscription.manage' });
- assert.strictEqual(trs.status, 200, JSON.stringify(trs.body));
- assert.strictEqual(trs.body.scope, 'events.subscription.manage', 'Trade manages its Events subscriptions');
// Go-live fan-out accepts Live's token (network.notifications.push); a narrower token is refused.
// Go-live fan-out accepts Live's token (network.notifications.push); a narrower token is refused.
r = await post('/internal/events/stream-live', {}, { authorization: `Bearer ${full}` });
r = await post('/internal/events/stream-live', {}, { authorization: `Bearer ${full}` });