@substrat-run/contract-tests 0.139.0 → 0.140.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/capability-suite.d.ts.map +1 -1
  2. package/dist/capability-suite.js +5 -0
  3. package/dist/capability-suite.js.map +1 -1
  4. package/dist/caused-by-suite.d.ts.map +1 -1
  5. package/dist/caused-by-suite.js +54 -10
  6. package/dist/caused-by-suite.js.map +1 -1
  7. package/dist/connect-link-suite.d.ts +19 -0
  8. package/dist/connect-link-suite.d.ts.map +1 -0
  9. package/dist/connect-link-suite.js +215 -0
  10. package/dist/connect-link-suite.js.map +1 -0
  11. package/dist/entity-state-migration-suite.d.ts +16 -0
  12. package/dist/entity-state-migration-suite.d.ts.map +1 -0
  13. package/dist/entity-state-migration-suite.js +305 -0
  14. package/dist/entity-state-migration-suite.js.map +1 -0
  15. package/dist/entity-state-module.d.ts +183 -0
  16. package/dist/entity-state-module.d.ts.map +1 -1
  17. package/dist/entity-state-module.js +139 -1
  18. package/dist/entity-state-module.js.map +1 -1
  19. package/dist/entity-state-suite.d.ts.map +1 -1
  20. package/dist/entity-state-suite.js +35 -12
  21. package/dist/entity-state-suite.js.map +1 -1
  22. package/dist/entity-trash-module.d.ts +439 -0
  23. package/dist/entity-trash-module.d.ts.map +1 -0
  24. package/dist/entity-trash-module.js +287 -0
  25. package/dist/entity-trash-module.js.map +1 -0
  26. package/dist/entity-trash-suite.d.ts +59 -0
  27. package/dist/entity-trash-suite.d.ts.map +1 -0
  28. package/dist/entity-trash-suite.js +568 -0
  29. package/dist/entity-trash-suite.js.map +1 -0
  30. package/dist/erasure-module.d.ts +259 -0
  31. package/dist/erasure-module.d.ts.map +1 -0
  32. package/dist/erasure-module.js +251 -0
  33. package/dist/erasure-module.js.map +1 -0
  34. package/dist/index.d.ts +13 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +13 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/list-suite.d.ts.map +1 -1
  39. package/dist/list-suite.js +101 -1
  40. package/dist/list-suite.js.map +1 -1
  41. package/dist/membership-executor-suite.d.ts.map +1 -1
  42. package/dist/membership-executor-suite.js +60 -9
  43. package/dist/membership-executor-suite.js.map +1 -1
  44. package/dist/migration-comments-suite.d.ts +3 -0
  45. package/dist/migration-comments-suite.d.ts.map +1 -0
  46. package/dist/migration-comments-suite.js +92 -0
  47. package/dist/migration-comments-suite.js.map +1 -0
  48. package/dist/migration-comments.d.ts +3 -0
  49. package/dist/migration-comments.d.ts.map +1 -0
  50. package/dist/migration-comments.js +50 -0
  51. package/dist/migration-comments.js.map +1 -0
  52. package/dist/migration-digest-suite.d.ts +3 -0
  53. package/dist/migration-digest-suite.d.ts.map +1 -0
  54. package/dist/migration-digest-suite.js +175 -0
  55. package/dist/migration-digest-suite.js.map +1 -0
  56. package/dist/modules.d.ts +542 -0
  57. package/dist/modules.d.ts.map +1 -1
  58. package/dist/modules.js +155 -7
  59. package/dist/modules.js.map +1 -1
  60. package/dist/peer-suite.d.ts +2 -1
  61. package/dist/peer-suite.d.ts.map +1 -1
  62. package/dist/peer-suite.js +103 -1
  63. package/dist/peer-suite.js.map +1 -1
  64. package/dist/permission-suite.d.ts.map +1 -1
  65. package/dist/permission-suite.js +515 -2
  66. package/dist/permission-suite.js.map +1 -1
  67. package/dist/scope-host-suite.d.ts.map +1 -1
  68. package/dist/scope-host-suite.js +54 -1
  69. package/dist/scope-host-suite.js.map +1 -1
  70. package/dist/split-cases.d.ts +12 -0
  71. package/dist/split-cases.d.ts.map +1 -0
  72. package/dist/split-cases.js +59 -0
  73. package/dist/split-cases.js.map +1 -0
  74. package/dist/subject-erasure-suite.d.ts +6 -0
  75. package/dist/subject-erasure-suite.d.ts.map +1 -0
  76. package/dist/subject-erasure-suite.js +287 -0
  77. package/dist/subject-erasure-suite.js.map +1 -0
  78. package/dist/switch-audit-fault.d.ts +48 -0
  79. package/dist/switch-audit-fault.d.ts.map +1 -0
  80. package/dist/switch-audit-fault.js +80 -0
  81. package/dist/switch-audit-fault.js.map +1 -0
  82. package/dist/system-switch-suite.d.ts +2 -1
  83. package/dist/system-switch-suite.d.ts.map +1 -1
  84. package/dist/system-switch-suite.js +90 -0
  85. package/dist/system-switch-suite.js.map +1 -1
  86. package/dist/vertical-events-suite.d.ts +41 -0
  87. package/dist/vertical-events-suite.d.ts.map +1 -1
  88. package/dist/vertical-events-suite.js +55 -0
  89. package/dist/vertical-events-suite.js.map +1 -1
  90. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
2
  import { connectorCalls, connectorTestFetch, resetConnectorCalls } from './connector-fixture.js';
3
- import { connectionId, dataSubjectId, domainEvent, errorCodeOf, moduleId, SCOPE_GATE_REASONS, eventId, instant, moduleManifest, orgId, AUTO_ADMISSION_NOTE, permissionKey, platformActorId, platformRequestId, principalId, scopeId, tenantId, SCOPE_QUERY_ROW_MAX, KERNEL_AUTHORED_EVENT_TYPES, SWEEP_RUNS_KIND, SCOPE_TABLE_PAGE_MAX, } from '@substrat-run/contracts';
3
+ import { connectionId, dataSubjectId, domainEvent, errorCodeOf, moduleId, SCOPE_GATE_REASONS, eventId, instant, moduleManifest, orgId, AUTO_ADMISSION_NOTE, permissionKey, platformActorId, platformRequestId, principalId, scopeId, tenantId, SCOPE_QUERY_ROW_MAX, KERNEL_AUTHORED_EVENT_TYPES, EMAIL_SENT, PLATFORM_REQUEST_ENTITY_TYPE, SEND_EMAIL_KIND, SWEEP_RUNS_KIND, SCOPE_TABLE_PAGE_MAX, } from '@substrat-run/contracts';
4
4
  import { INERT_SCOPE_REASON, isSearchIndexTable, platformIntentFailureMessage, REDACTED_DELIVERY_NOTE, REDACTED_FAILURE_NOTE, REDACTED_INTENT_MARKER, runPlatformSweep, startPlatformSweeper, createUlid, ulid, } from '@substrat-run/kernel';
5
5
  import { billedMod, contractTestBareOps, contractTestInitialModules, gateModManifest, lateMod, TEST_LIFECYCLE, testModManifest, victimModManifest, } from './modules.js';
6
6
  /**
@@ -273,6 +273,45 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
273
273
  expect(settled.status).toBe('done');
274
274
  expect(JSON.parse(settled.result)).toEqual({ scopeId: 'NEWSITE' });
275
275
  });
276
+ it('a settle carrying an outcome event writes it once, as the kernel, with the settle (#2102)', async () => {
277
+ const stub = await host.getScope(alice, t1, s1);
278
+ const mail = { to: 'ada@example.com', subject: 'Hej', html: '<p>Hej</p>', text: 'Hej' };
279
+ const id = await stub.invoke('platform/request', { kind: SEND_EMAIL_KIND, payload: mail });
280
+ const mine = () => stub
281
+ .invoke('platform/outcome-events')
282
+ .then((rows) => rows.filter((r) => JSON.parse(r.payload).request === id));
283
+ const event = (request) => ({
284
+ type: EMAIL_SENT,
285
+ entity: { entityType: PLATFORM_REQUEST_ENTITY_TYPE, entityId: id },
286
+ payload: {
287
+ request: platformRequestId.parse(request),
288
+ about: null,
289
+ sender: 'platform',
290
+ messageId: 'msg-1',
291
+ attempts: 1,
292
+ code: null,
293
+ status: null,
294
+ },
295
+ });
296
+ // Refused before anything is written: an event on a `pending` settle, or one naming
297
+ // another request. The row stays exactly as it was.
298
+ await expect(host.settlePlatformRequest(t1, s1, platformRequestId.parse(id), { status: 'pending', event: event(id) })).rejects.toThrow();
299
+ await expect(host.settlePlatformRequest(t1, s1, platformRequestId.parse(id), { status: 'done', event: event(ulid()) })).rejects.toThrow();
300
+ expect((await host.listPlatformRequests(t1, s1)).find((r) => r.id === id)?.attempts).toBe(0);
301
+ expect(await mine()).toEqual([]);
302
+ await host.settlePlatformRequest(t1, s1, platformRequestId.parse(id), { status: 'done', event: event(id) });
303
+ const written = await mine();
304
+ expect(written).toHaveLength(1);
305
+ expect(written[0].type).toBe(EMAIL_SENT);
306
+ expect(JSON.parse(written[0].actor)).toEqual({ system: '@substrat-run/kernel' });
307
+ expect([written[0].entity_type, written[0].entity_id]).toEqual([PLATFORM_REQUEST_ENTITY_TYPE, id]);
308
+ expect(JSON.parse(written[0].payload)).toMatchObject({ request: id, messageId: 'msg-1', sender: 'platform' });
309
+ // A repeated settle finds the row terminal: it moves nothing, so it writes nothing.
310
+ await host.settlePlatformRequest(t1, s1, platformRequestId.parse(id), { status: 'failed', event: event(id) });
311
+ expect(await mine()).toHaveLength(1);
312
+ const row = (await stub.invoke('platform/read-requests')).find((r) => r.id === id);
313
+ expect(row.status).toBe('done');
314
+ });
276
315
  it('a transient failure keeps the intent pending and preserves a two-phase result (retry)', async () => {
277
316
  const stub = await host.getScope(alice, t1, s1);
278
317
  const id = await stub.invoke('platform/request', { kind: 'provision-sibling', payload: {} });
@@ -4400,6 +4439,20 @@ export function scopeHostContractSuite(adapterName, makeFixture, opts = {}) {
4400
4439
  expect(rotated?.after).toMatchObject({ id: row.id, rotatedBy: officeAdmin });
4401
4440
  expect(JSON.stringify(log)).not.toContain('tok-relay-rotated');
4402
4441
  });
4442
+ it('a rotation sets the expiry, keeps it when omitted, and clears it with null (#2100)', async () => {
4443
+ const [row] = await host.admin.listConnections(staff, { tenantId: t1, vertical: 'callout' });
4444
+ const expiry = async () => (await host.admin.listConnections(staff, { tenantId: t1, vertical: 'callout' })).find((c) => c.id === row.id)
4445
+ .expiresAt;
4446
+ const at = '2027-10-07T12:00:00.000Z';
4447
+ await host.admin.updateConnectionSecret(staff, row.id, { accessToken: 'tok-dated' }, at);
4448
+ expect(await expiry()).toBe(at);
4449
+ await host.admin.updateConnectionSecret(staff, row.id, { accessToken: 'tok-kept' });
4450
+ expect(await expiry()).toBe(at);
4451
+ // The credential that had an end was replaced by one that has none (a certificate → a
4452
+ // client secret): the old end must not stay on the connection, reading as this one's.
4453
+ await host.admin.updateConnectionSecret(staff, row.id, { accessToken: 'tok-undated' }, null);
4454
+ expect(await expiry()).toBeNull();
4455
+ });
4403
4456
  it('records health, and a success clears a prior error', async () => {
4404
4457
  const [row] = await host.admin.listConnections(staff, {
4405
4458
  tenantId: t1,