@nylorun/runtime 0.19.1-beta → 0.21.0-beta

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 (137) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +22 -13
  3. package/dist/adapters/streams/s2.js +5 -11
  4. package/dist/api/components.d.ts +326 -205
  5. package/dist/api/components.js +3 -3
  6. package/dist/api/http/app.js +2 -0
  7. package/dist/api/http/define.d.ts +3 -2
  8. package/dist/api/http/define.js +10 -11
  9. package/dist/api/http/routes/mcp.d.ts +9 -0
  10. package/dist/api/http/routes/mcp.js +32 -0
  11. package/dist/api/http/routes/vaults.d.ts +1 -9
  12. package/dist/api/http/routes/vaults.js +3 -103
  13. package/dist/api/openapi.js +37 -6
  14. package/dist/artifacts/media-types.d.ts +2 -0
  15. package/dist/artifacts/media-types.js +5 -0
  16. package/dist/execution/types.d.ts +1 -1
  17. package/dist/gates/http-tool.d.ts +7 -0
  18. package/dist/gates/http-tool.js +34 -3
  19. package/dist/gates/mcp-handler.d.ts +4 -1
  20. package/dist/gates/mcp-handler.js +64 -8
  21. package/dist/gates/tenant-vaults.d.ts +9 -15
  22. package/dist/gates/tenant-vaults.js +9 -17
  23. package/dist/gates/tool-client.js +36 -17
  24. package/dist/gates/tool-contract.d.ts +19 -3
  25. package/dist/gates/tool-contract.js +9 -3
  26. package/dist/gates/tool-gate.d.ts +2 -2
  27. package/dist/harness/calls.d.ts +2 -0
  28. package/dist/harness/calls.js +13 -3
  29. package/dist/harness-api/record.d.ts +7 -6
  30. package/dist/harness-api/record.js +99 -17
  31. package/dist/harness-api/server.js +35 -27
  32. package/dist/harness-api/start.js +2 -1
  33. package/dist/host/app.d.ts +3 -0
  34. package/dist/host/app.js +33 -4
  35. package/dist/host/config-for.d.ts +0 -2
  36. package/dist/host/config-for.js +0 -1
  37. package/dist/host/create-host.d.ts +6 -0
  38. package/dist/host/create-host.js +1 -0
  39. package/dist/host/gates.js +0 -1
  40. package/dist/host/main.js +24 -7
  41. package/dist/host/stack-config.d.ts +5 -8
  42. package/dist/host/stack-config.js +9 -20
  43. package/dist/index.d.ts +0 -1
  44. package/dist/infra/index.d.ts +2 -1
  45. package/dist/infra/index.js +0 -1
  46. package/dist/infra/readiness.d.ts +6 -6
  47. package/dist/infra/readiness.js +2 -5
  48. package/dist/keys/client.js +1 -9
  49. package/dist/keys/keys.d.ts +11 -13
  50. package/dist/keys/keys.js +5 -7
  51. package/dist/management-openapi.json +671 -378
  52. package/dist/mcp/connect.d.ts +159 -13
  53. package/dist/mcp/connect.js +538 -55
  54. package/dist/mcp/pool.d.ts +11 -2
  55. package/dist/mcp/pool.js +74 -27
  56. package/dist/mcp/preview.d.ts +35 -0
  57. package/dist/mcp/preview.js +215 -0
  58. package/dist/mcp/snapshot.d.ts +79 -5
  59. package/dist/mcp/snapshot.js +145 -27
  60. package/dist/model/catalog.d.ts +14 -0
  61. package/dist/model/catalog.js +14 -1
  62. package/dist/model/pi-model.js +36 -2
  63. package/dist/openapi.json +644 -266
  64. package/dist/redact.d.ts +19 -1
  65. package/dist/redact.js +42 -13
  66. package/dist/sandbox/session-sandbox.d.ts +7 -0
  67. package/dist/sandbox/session-sandbox.js +89 -28
  68. package/dist/store/postgres/connect.d.ts +10 -0
  69. package/dist/store/postgres/connect.js +30 -3
  70. package/dist/store/postgres/control.d.ts +14 -0
  71. package/dist/store/postgres/control.js +187 -0
  72. package/dist/store/postgres/drizzle/0015_control_signals.sql +11 -0
  73. package/dist/store/postgres/drizzle/0016_mcp_oauth_removed.sql +5 -0
  74. package/dist/store/postgres/drizzle/meta/_journal.json +14 -0
  75. package/dist/store/postgres/schema.d.ts +122 -261
  76. package/dist/store/postgres/schema.js +22 -36
  77. package/dist/store/postgres/store.js +16 -18
  78. package/dist/store/postgres/tenant.d.ts +14 -0
  79. package/dist/store/postgres/tenant.js +22 -2
  80. package/dist/store/types.d.ts +42 -8
  81. package/dist/streams/types.d.ts +6 -29
  82. package/dist/streams/types.js +5 -4
  83. package/dist/tenant/artifact-tool.d.ts +9 -1
  84. package/dist/tenant/artifact-tool.js +113 -9
  85. package/dist/tenant/auth.d.ts +16 -6
  86. package/dist/tenant/auth.js +41 -17
  87. package/dist/tenant/commands.js +10 -6
  88. package/dist/tenant/context.d.ts +9 -6
  89. package/dist/tenant/control.d.ts +26 -0
  90. package/dist/tenant/control.js +35 -0
  91. package/dist/tenant/effects.d.ts +2 -2
  92. package/dist/tenant/effects.js +20 -5
  93. package/dist/tenant/ephemeral.d.ts +0 -6
  94. package/dist/tenant/ephemeral.js +1 -1
  95. package/dist/tenant/http.d.ts +4 -2
  96. package/dist/tenant/http.js +4 -2
  97. package/dist/tenant/identity-file.d.ts +16 -12
  98. package/dist/tenant/identity-file.js +41 -29
  99. package/dist/tenant/issuers.d.ts +4 -3
  100. package/dist/tenant/issuers.js +22 -16
  101. package/dist/tenant/outbound.d.ts +14 -5
  102. package/dist/tenant/outbound.js +21 -9
  103. package/dist/tenant/reset.d.ts +2 -2
  104. package/dist/tenant/reset.js +8 -2
  105. package/dist/tenant/resource-server.d.ts +56 -0
  106. package/dist/tenant/resource-server.js +62 -0
  107. package/dist/tenant/runtime.d.ts +1 -1
  108. package/dist/tenant/runtime.js +16 -15
  109. package/dist/tenant/scheduler.d.ts +1 -1
  110. package/dist/tenant/scheduler.js +1 -1
  111. package/dist/tenant/sessions.js +20 -3
  112. package/dist/tenant/store-pg.js +9 -0
  113. package/dist/tenant/streams.d.ts +16 -22
  114. package/dist/tenant/streams.js +7 -87
  115. package/dist/tenant/sweep.js +9 -1
  116. package/dist/tenant/tool-results.d.ts +57 -0
  117. package/dist/tenant/tool-results.js +298 -0
  118. package/dist/tenant/tool-search.d.ts +43 -0
  119. package/dist/tenant/tool-search.js +100 -0
  120. package/dist/tenant/transcript.d.ts +108 -0
  121. package/dist/tenant/transcript.js +13 -0
  122. package/dist/tenant/types.d.ts +0 -14
  123. package/dist/vault/crypto.d.ts +0 -7
  124. package/dist/vault/crypto.js +0 -16
  125. package/dist/vault/headers.d.ts +17 -0
  126. package/dist/vault/headers.js +61 -0
  127. package/dist/vault/service.d.ts +11 -68
  128. package/dist/vault/service.js +83 -438
  129. package/dist/vault/sources.d.ts +20 -48
  130. package/dist/vault/sources.js +25 -189
  131. package/dist/version.d.ts +1 -1
  132. package/dist/version.js +1 -1
  133. package/package.json +3 -3
  134. package/dist/streams/control.d.ts +0 -13
  135. package/dist/streams/control.js +0 -25
  136. package/dist/vault/oauth.d.ts +0 -55
  137. package/dist/vault/oauth.js +0 -186
@@ -1048,14 +1048,14 @@ export declare const vaultCredentials: import("drizzle-orm/pg-core").PgTableWith
1048
1048
  tableName: "vault_credentials";
1049
1049
  dataType: "string";
1050
1050
  columnType: "PgText";
1051
- data: "bearer" | "model" | "oauth";
1051
+ data: "bearer" | "headers" | "model";
1052
1052
  driverParam: string;
1053
1053
  notNull: true;
1054
1054
  hasDefault: false;
1055
1055
  isPrimaryKey: false;
1056
1056
  isAutoincrement: false;
1057
1057
  hasRuntimeDefault: false;
1058
- enumValues: ["bearer", "oauth", "model"];
1058
+ enumValues: ["bearer", "headers", "model"];
1059
1059
  baseColumn: never;
1060
1060
  identity: undefined;
1061
1061
  generated: undefined;
@@ -1442,264 +1442,6 @@ export declare const vaultIdempotency: import("drizzle-orm/pg-core").PgTableWith
1442
1442
  };
1443
1443
  dialect: 'pg';
1444
1444
  }>;
1445
- /**
1446
- * An MCP OAuth connect between its start and its callback (F9 C2): found by the SHA-256 of its
1447
- * `state`, used once, for ten minutes. The PKCE verifier and any client secret are sealed under
1448
- * the vault key (`sealBytes`), which only the keys module holds.
1449
- */
1450
- export declare const oauthPending: import("drizzle-orm/pg-core").PgTableWithColumns<{
1451
- name: "oauth_pending";
1452
- schema: "nylorun";
1453
- columns: {
1454
- stateHash: import("drizzle-orm/pg-core").PgColumn<{
1455
- name: "stateHash";
1456
- tableName: "oauth_pending";
1457
- dataType: "string";
1458
- columnType: "PgText";
1459
- data: string;
1460
- driverParam: string;
1461
- notNull: true;
1462
- hasDefault: false;
1463
- isPrimaryKey: true;
1464
- isAutoincrement: false;
1465
- hasRuntimeDefault: false;
1466
- enumValues: [string, ...string[]];
1467
- baseColumn: never;
1468
- identity: undefined;
1469
- generated: undefined;
1470
- }, {}, {}>;
1471
- vaultId: import("drizzle-orm/pg-core").PgColumn<{
1472
- name: "vaultId";
1473
- tableName: "oauth_pending";
1474
- dataType: "string";
1475
- columnType: "PgText";
1476
- data: string;
1477
- driverParam: string;
1478
- notNull: true;
1479
- hasDefault: false;
1480
- isPrimaryKey: false;
1481
- isAutoincrement: false;
1482
- hasRuntimeDefault: false;
1483
- enumValues: [string, ...string[]];
1484
- baseColumn: never;
1485
- identity: undefined;
1486
- generated: undefined;
1487
- }, {}, {}>;
1488
- server: import("drizzle-orm/pg-core").PgColumn<{
1489
- name: "server";
1490
- tableName: "oauth_pending";
1491
- dataType: "string";
1492
- columnType: "PgText";
1493
- data: string;
1494
- driverParam: string;
1495
- notNull: true;
1496
- hasDefault: false;
1497
- isPrimaryKey: false;
1498
- isAutoincrement: false;
1499
- hasRuntimeDefault: false;
1500
- enumValues: [string, ...string[]];
1501
- baseColumn: never;
1502
- identity: undefined;
1503
- generated: undefined;
1504
- }, {}, {}>;
1505
- url: import("drizzle-orm/pg-core").PgColumn<{
1506
- name: "url";
1507
- tableName: "oauth_pending";
1508
- dataType: "string";
1509
- columnType: "PgText";
1510
- data: string;
1511
- driverParam: string;
1512
- notNull: true;
1513
- hasDefault: false;
1514
- isPrimaryKey: false;
1515
- isAutoincrement: false;
1516
- hasRuntimeDefault: false;
1517
- enumValues: [string, ...string[]];
1518
- baseColumn: never;
1519
- identity: undefined;
1520
- generated: undefined;
1521
- }, {}, {}>;
1522
- tokenEndpoint: import("drizzle-orm/pg-core").PgColumn<{
1523
- name: "tokenEndpoint";
1524
- tableName: "oauth_pending";
1525
- dataType: "string";
1526
- columnType: "PgText";
1527
- data: string;
1528
- driverParam: string;
1529
- notNull: true;
1530
- hasDefault: false;
1531
- isPrimaryKey: false;
1532
- isAutoincrement: false;
1533
- hasRuntimeDefault: false;
1534
- enumValues: [string, ...string[]];
1535
- baseColumn: never;
1536
- identity: undefined;
1537
- generated: undefined;
1538
- }, {}, {}>;
1539
- clientId: import("drizzle-orm/pg-core").PgColumn<{
1540
- name: "clientId";
1541
- tableName: "oauth_pending";
1542
- dataType: "string";
1543
- columnType: "PgText";
1544
- data: string;
1545
- driverParam: string;
1546
- notNull: true;
1547
- hasDefault: false;
1548
- isPrimaryKey: false;
1549
- isAutoincrement: false;
1550
- hasRuntimeDefault: false;
1551
- enumValues: [string, ...string[]];
1552
- baseColumn: never;
1553
- identity: undefined;
1554
- generated: undefined;
1555
- }, {}, {}>;
1556
- tokenEndpointAuth: import("drizzle-orm/pg-core").PgColumn<{
1557
- name: "tokenEndpointAuth";
1558
- tableName: "oauth_pending";
1559
- dataType: "string";
1560
- columnType: "PgText";
1561
- data: "client_secret_basic" | "client_secret_post" | "none";
1562
- driverParam: string;
1563
- notNull: true;
1564
- hasDefault: false;
1565
- isPrimaryKey: false;
1566
- isAutoincrement: false;
1567
- hasRuntimeDefault: false;
1568
- enumValues: ["none", "client_secret_basic", "client_secret_post"];
1569
- baseColumn: never;
1570
- identity: undefined;
1571
- generated: undefined;
1572
- }, {}, {}>;
1573
- resource: import("drizzle-orm/pg-core").PgColumn<{
1574
- name: "resource";
1575
- tableName: "oauth_pending";
1576
- dataType: "string";
1577
- columnType: "PgText";
1578
- data: string;
1579
- driverParam: string;
1580
- notNull: false;
1581
- hasDefault: false;
1582
- isPrimaryKey: false;
1583
- isAutoincrement: false;
1584
- hasRuntimeDefault: false;
1585
- enumValues: [string, ...string[]];
1586
- baseColumn: never;
1587
- identity: undefined;
1588
- generated: undefined;
1589
- }, {}, {}>;
1590
- kekId: import("drizzle-orm/pg-core").PgColumn<{
1591
- name: "kekId";
1592
- tableName: "oauth_pending";
1593
- dataType: "string";
1594
- columnType: "PgText";
1595
- data: string;
1596
- driverParam: string;
1597
- notNull: true;
1598
- hasDefault: false;
1599
- isPrimaryKey: false;
1600
- isAutoincrement: false;
1601
- hasRuntimeDefault: false;
1602
- enumValues: [string, ...string[]];
1603
- baseColumn: never;
1604
- identity: undefined;
1605
- generated: undefined;
1606
- }, {}, {}>;
1607
- clientSecret: import("drizzle-orm/pg-core").PgColumn<{
1608
- name: "clientSecret";
1609
- tableName: "oauth_pending";
1610
- dataType: "custom";
1611
- columnType: "PgCustomColumn";
1612
- data: Uint8Array<ArrayBufferLike>;
1613
- driverParam: Buffer<ArrayBufferLike>;
1614
- notNull: false;
1615
- hasDefault: false;
1616
- isPrimaryKey: false;
1617
- isAutoincrement: false;
1618
- hasRuntimeDefault: false;
1619
- enumValues: undefined;
1620
- baseColumn: never;
1621
- identity: undefined;
1622
- generated: undefined;
1623
- }, {}, {
1624
- pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
1625
- }>;
1626
- codeVerifier: import("drizzle-orm/pg-core").PgColumn<{
1627
- name: "codeVerifier";
1628
- tableName: "oauth_pending";
1629
- dataType: "custom";
1630
- columnType: "PgCustomColumn";
1631
- data: Uint8Array<ArrayBufferLike>;
1632
- driverParam: Buffer<ArrayBufferLike>;
1633
- notNull: true;
1634
- hasDefault: false;
1635
- isPrimaryKey: false;
1636
- isAutoincrement: false;
1637
- hasRuntimeDefault: false;
1638
- enumValues: undefined;
1639
- baseColumn: never;
1640
- identity: undefined;
1641
- generated: undefined;
1642
- }, {}, {
1643
- pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
1644
- }>;
1645
- redirectUri: import("drizzle-orm/pg-core").PgColumn<{
1646
- name: "redirectUri";
1647
- tableName: "oauth_pending";
1648
- dataType: "string";
1649
- columnType: "PgText";
1650
- data: string;
1651
- driverParam: string;
1652
- notNull: true;
1653
- hasDefault: false;
1654
- isPrimaryKey: false;
1655
- isAutoincrement: false;
1656
- hasRuntimeDefault: false;
1657
- enumValues: [string, ...string[]];
1658
- baseColumn: never;
1659
- identity: undefined;
1660
- generated: undefined;
1661
- }, {}, {}>;
1662
- expiresAt: import("drizzle-orm/pg-core").PgColumn<{
1663
- name: "expiresAt";
1664
- tableName: "oauth_pending";
1665
- dataType: "custom";
1666
- columnType: "PgCustomColumn";
1667
- data: string;
1668
- driverParam: string;
1669
- notNull: true;
1670
- hasDefault: false;
1671
- isPrimaryKey: false;
1672
- isAutoincrement: false;
1673
- hasRuntimeDefault: false;
1674
- enumValues: undefined;
1675
- baseColumn: never;
1676
- identity: undefined;
1677
- generated: undefined;
1678
- }, {}, {
1679
- pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
1680
- }>;
1681
- createdAt: import("drizzle-orm/pg-core").PgColumn<{
1682
- name: "createdAt";
1683
- tableName: "oauth_pending";
1684
- dataType: "custom";
1685
- columnType: "PgCustomColumn";
1686
- data: string;
1687
- driverParam: string;
1688
- notNull: true;
1689
- hasDefault: false;
1690
- isPrimaryKey: false;
1691
- isAutoincrement: false;
1692
- hasRuntimeDefault: false;
1693
- enumValues: undefined;
1694
- baseColumn: never;
1695
- identity: undefined;
1696
- generated: undefined;
1697
- }, {}, {
1698
- pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
1699
- }>;
1700
- };
1701
- dialect: 'pg';
1702
- }>;
1703
1445
  export declare const tenantSettings: import("drizzle-orm/pg-core").PgTableWithColumns<{
1704
1446
  name: "tenant_settings";
1705
1447
  schema: "nylorun";
@@ -3478,6 +3220,126 @@ export declare const definitionFileUses: import("drizzle-orm/pg-core").PgTableWi
3478
3220
  };
3479
3221
  dialect: 'pg';
3480
3222
  }>;
3223
+ /**
3224
+ * The control bus (D21, D48): signals between the processes that have the Tenant open,
3225
+ * written in the transaction that commits what they announce and notified on
3226
+ * `nylorun_control` at commit (`control.ts`). A row outlives its notification so a process
3227
+ * whose listener was down catches up; the Tenant sweep deletes old ones. `created_at` is the
3228
+ * insert's own clock (`clock_timestamp()`), not its transaction's start.
3229
+ */
3230
+ export declare const controlSignals: import("drizzle-orm/pg-core").PgTableWithColumns<{
3231
+ name: "control_signals";
3232
+ schema: "nylorun";
3233
+ columns: {
3234
+ id: import("drizzle-orm/pg-core").PgColumn<{
3235
+ name: "id";
3236
+ tableName: "control_signals";
3237
+ dataType: "number";
3238
+ columnType: "PgBigInt53";
3239
+ data: number;
3240
+ driverParam: string | number;
3241
+ notNull: true;
3242
+ hasDefault: true;
3243
+ isPrimaryKey: true;
3244
+ isAutoincrement: false;
3245
+ hasRuntimeDefault: false;
3246
+ enumValues: undefined;
3247
+ baseColumn: never;
3248
+ identity: "always";
3249
+ generated: undefined;
3250
+ }, {}, {}>;
3251
+ kind: import("drizzle-orm/pg-core").PgColumn<{
3252
+ name: "kind";
3253
+ tableName: "control_signals";
3254
+ dataType: "string";
3255
+ columnType: "PgText";
3256
+ data: string;
3257
+ driverParam: string;
3258
+ notNull: true;
3259
+ hasDefault: false;
3260
+ isPrimaryKey: false;
3261
+ isAutoincrement: false;
3262
+ hasRuntimeDefault: false;
3263
+ enumValues: [string, ...string[]];
3264
+ baseColumn: never;
3265
+ identity: undefined;
3266
+ generated: undefined;
3267
+ }, {}, {}>;
3268
+ sessionId: import("drizzle-orm/pg-core").PgColumn<{
3269
+ name: "sessionId";
3270
+ tableName: "control_signals";
3271
+ dataType: "custom";
3272
+ columnType: "PgCustomColumn";
3273
+ data: string;
3274
+ driverParam: string;
3275
+ notNull: false;
3276
+ hasDefault: false;
3277
+ isPrimaryKey: false;
3278
+ isAutoincrement: false;
3279
+ hasRuntimeDefault: false;
3280
+ enumValues: undefined;
3281
+ baseColumn: never;
3282
+ identity: undefined;
3283
+ generated: undefined;
3284
+ }, {}, {
3285
+ pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
3286
+ }>;
3287
+ turnId: import("drizzle-orm/pg-core").PgColumn<{
3288
+ name: "turnId";
3289
+ tableName: "control_signals";
3290
+ dataType: "custom";
3291
+ columnType: "PgCustomColumn";
3292
+ data: string;
3293
+ driverParam: string;
3294
+ notNull: false;
3295
+ hasDefault: false;
3296
+ isPrimaryKey: false;
3297
+ isAutoincrement: false;
3298
+ hasRuntimeDefault: false;
3299
+ enumValues: undefined;
3300
+ baseColumn: never;
3301
+ identity: undefined;
3302
+ generated: undefined;
3303
+ }, {}, {
3304
+ pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
3305
+ }>;
3306
+ generation: import("drizzle-orm/pg-core").PgColumn<{
3307
+ name: "generation";
3308
+ tableName: "control_signals";
3309
+ dataType: "number";
3310
+ columnType: "PgInteger";
3311
+ data: number;
3312
+ driverParam: string | number;
3313
+ notNull: false;
3314
+ hasDefault: false;
3315
+ isPrimaryKey: false;
3316
+ isAutoincrement: false;
3317
+ hasRuntimeDefault: false;
3318
+ enumValues: undefined;
3319
+ baseColumn: never;
3320
+ identity: undefined;
3321
+ generated: undefined;
3322
+ }, {}, {}>;
3323
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
3324
+ name: "createdAt";
3325
+ tableName: "control_signals";
3326
+ dataType: "string";
3327
+ columnType: "PgTimestampString";
3328
+ data: string;
3329
+ driverParam: string;
3330
+ notNull: true;
3331
+ hasDefault: true;
3332
+ isPrimaryKey: false;
3333
+ isAutoincrement: false;
3334
+ hasRuntimeDefault: false;
3335
+ enumValues: undefined;
3336
+ baseColumn: never;
3337
+ identity: undefined;
3338
+ generated: undefined;
3339
+ }, {}, {}>;
3340
+ };
3341
+ dialect: 'pg';
3342
+ }>;
3481
3343
  /**
3482
3344
  * Each sandbox's lifecycle stream (`nylorun.sandbox-event/1`), numbered from 0 per sandbox id.
3483
3345
  * Written only by the record module; not published to the stream relay.
@@ -3804,7 +3666,6 @@ export type VaultRow = typeof vaults.$inferSelect;
3804
3666
  export type VaultCredentialRow = typeof vaultCredentials.$inferSelect;
3805
3667
  export type VaultAuditRow = Omit<typeof vaultAudit.$inferSelect, "ord">;
3806
3668
  export type VaultIdempotencyRow = typeof vaultIdempotency.$inferSelect;
3807
- export type OAuthPendingRow = typeof oauthPending.$inferSelect;
3808
3669
  export type SigningKeyRow = typeof signingKeys.$inferSelect;
3809
3670
  export type ModelUsageRow = typeof modelUsage.$inferSelect;
3810
3671
  export type ModelBudgetRow = typeof modelBudgets.$inferSelect;
@@ -129,8 +129,8 @@ export const vaultCredentials = nylorun.table("vault_credentials", {
129
129
  id: textC().primaryKey(),
130
130
  vaultId: text().notNull(),
131
131
  name: text().notNull(),
132
- type: text({ enum: ["bearer", "oauth", "model"] }).notNull(),
133
- /** JSON text of the non-secret binding (url, or provider and model). */
132
+ type: text({ enum: ["bearer", "headers", "model"] }).notNull(),
133
+ /** JSON text of the non-secret binding: url (and via, identity, header names), or provider and model. */
134
134
  bindingJson: text().notNull(),
135
135
  expiresAt: text(),
136
136
  createdAt: textC().notNull(),
@@ -165,40 +165,6 @@ export const vaultIdempotency = nylorun.table("vault_idempotency", {
165
165
  /** JSON text of the original response. */
166
166
  response: text().notNull(),
167
167
  });
168
- /**
169
- * An MCP OAuth connect between its start and its callback (F9 C2): found by the SHA-256 of its
170
- * `state`, used once, for ten minutes. The PKCE verifier and any client secret are sealed under
171
- * the vault key (`sealBytes`), which only the keys module holds.
172
- */
173
- export const oauthPending = nylorun.table("oauth_pending", {
174
- stateHash: text().primaryKey(),
175
- vaultId: text().notNull(),
176
- /** The MCP server's name in the agent, the credential's name. */
177
- server: text().notNull(),
178
- /** The MCP server's URL (normalized): the credential's binding. */
179
- url: text().notNull(),
180
- tokenEndpoint: text().notNull(),
181
- clientId: text().notNull(),
182
- /** How the client authenticates at the token endpoint: `none`, `client_secret_basic` or `client_secret_post`. */
183
- tokenEndpointAuth: text({ enum: ["none", "client_secret_basic", "client_secret_post"] }).notNull(),
184
- /** The RFC 8707 resource indicator sent with the authorization request, if any. */
185
- resource: text(),
186
- kekId: text().notNull(),
187
- /** Sealed; null for a public client. */
188
- clientSecret: bytes(),
189
- /** Sealed. */
190
- codeVerifier: bytes().notNull(),
191
- redirectUri: text().notNull(),
192
- expiresAt: textC().notNull(),
193
- createdAt: textC().notNull(),
194
- }, (t) => [
195
- foreignKey({
196
- name: "oauth_pending_vault_id_fkey",
197
- columns: [t.vaultId],
198
- foreignColumns: [vaults.id],
199
- }).onDelete("cascade"),
200
- index("oauth_pending_expires").on(t.expiresAt),
201
- ]);
202
168
  export const tenantSettings = nylorun.table("tenant_settings", {
203
169
  key: text().primaryKey(),
204
170
  value: text().notNull(),
@@ -435,6 +401,26 @@ export const definitionFileUses = nylorun.table("definition_file_uses", {
435
401
  primaryKey({ name: "definition_file_uses_pkey", columns: [t.agentId, t.manifestHash, t.sha256] }),
436
402
  index("definition_file_uses_sha256").on(t.sha256),
437
403
  ]);
404
+ /**
405
+ * The control bus (D21, D48): signals between the processes that have the Tenant open,
406
+ * written in the transaction that commits what they announce and notified on
407
+ * `nylorun_control` at commit (`control.ts`). A row outlives its notification so a process
408
+ * whose listener was down catches up; the Tenant sweep deletes old ones. `created_at` is the
409
+ * insert's own clock (`clock_timestamp()`), not its transaction's start.
410
+ */
411
+ export const controlSignals = nylorun.table("control_signals", {
412
+ id: bigint({ mode: "number" }).primaryKey().generatedAlwaysAsIdentity(),
413
+ kind: text().notNull(),
414
+ sessionId: textC(),
415
+ turnId: textC(),
416
+ generation: integer(),
417
+ createdAt: timestamp({ withTimezone: true, mode: "string" })
418
+ .notNull()
419
+ .default(sql `clock_timestamp()`),
420
+ }, (t) => [
421
+ index("control_signals_created_at").on(t.createdAt),
422
+ check("control_signals_kind_check", sql `${t.kind} IN ('session.cancel', 'sessions.reset')`),
423
+ ]);
438
424
  // ---------------------------------------------------------------------------
439
425
  // nylorun_streams: the record
440
426
  /**
@@ -52,11 +52,12 @@ import { AsyncLocalStorage } from "node:async_hooks";
52
52
  import { and, count, eq, getTableColumns, gte, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
53
53
  import { appendEvent, appendSandboxEvent } from "../../record/index.js";
54
54
  import { OwnershipLostError, PrincipalRoleConflict } from "../ownership.js";
55
+ import { followControlSignals, pruneSignals, writeSignal } from "./control.js";
55
56
  import { database, driverError } from "./db.js";
56
57
  import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
57
58
  import { createPostgresRecordReader } from "./record.js";
58
59
  import { postgresRecordWriter, postgresSandboxRecordWriter } from "./record-writer.js";
59
- import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, sandboxEvents, sandboxResources, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, oauthPending, } from "./schema.js";
60
+ import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, sandboxEvents, sandboxResources, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, } from "./schema.js";
60
61
  export function createPostgresSessionStore(options) {
61
62
  return new PostgresSessionStore(options);
62
63
  }
@@ -175,6 +176,11 @@ class PostgresSessionStore {
175
176
  return { ok: false, schemaVersion: 0, expectedSchemaVersion };
176
177
  }
177
178
  }
179
+ followSignals(onSignal, options) {
180
+ if (this.closed)
181
+ throw new Error("SessionStore is closed");
182
+ return followControlSignals(this.sql, this.db, onSignal, options);
183
+ }
178
184
  /** Rejects new transactions and waits for running ones. Does not end the pool. */
179
185
  async close() {
180
186
  this.closed = true;
@@ -583,6 +589,15 @@ class PostgresTx {
583
589
  definitions: row.definitions,
584
590
  };
585
591
  }
592
+ // --- control bus (D21) ---------------------------------------------------
593
+ async signal(signal) {
594
+ this.check();
595
+ await writeSignal(this.db, signal);
596
+ }
597
+ async pruneSignals(before) {
598
+ this.check();
599
+ return pruneSignals(this.db, before);
600
+ }
586
601
  // --- basin generations --------------------------------------------------
587
602
  async basinGenerations() {
588
603
  this.check();
@@ -750,23 +765,6 @@ class PostgresTx {
750
765
  this.check();
751
766
  await this.db.insert(vaultIdempotency).values(row);
752
767
  }
753
- async insertOAuthPending(row) {
754
- this.check();
755
- await this.db.insert(oauthPending).values(row);
756
- }
757
- async takeOAuthPending(stateHash) {
758
- this.check();
759
- const [row] = await this.db
760
- .delete(oauthPending)
761
- .where(eq(oauthPending.stateHash, stateHash))
762
- .returning();
763
- return row;
764
- }
765
- async deleteExpiredOAuthPending(now) {
766
- this.check();
767
- const result = await this.db.delete(oauthPending).where(lt(oauthPending.expiresAt, now));
768
- return result.count;
769
- }
770
768
  // --- signing keys --------------------------------------------------------
771
769
  async lockSigningKeys() {
772
770
  this.check();
@@ -11,6 +11,8 @@
11
11
  * tables of a pre-release build of it. It is never touched: this release starts fresh.
12
12
  * 2. Apply the missing migrations (`migrate.ts`). A database with migrations this Runtime
13
13
  * does not know is `schema-too-new`; a migration Postgres rejects is `migration-failed`.
14
+ * `0016_mcp_oauth_removed` deletes the vault's MCP OAuth credentials (protocol 10), each
15
+ * with an audit row; the open returns them (`removedCredentials`) for a boot warning.
14
16
  * 3. When `nylorun.tenant` is empty, create the Tenant: its row (id, name, created time) and
15
17
  * its first principals. A database whose row is gone but that holds a Tenant's data
16
18
  * (principals, sessions, agents, vaults, keys) is `envelope-invalid`, never given a new
@@ -74,6 +76,18 @@ export interface OpenedTenantDatabase {
74
76
  from: number;
75
77
  to: number;
76
78
  };
79
+ /**
80
+ * The MCP OAuth credentials this call's migration `0016_mcp_oauth_removed` deleted (protocol
81
+ * 10), from the audit rows it wrote: the Host names each in a boot warning. Empty otherwise.
82
+ */
83
+ removedCredentials: RemovedCredential[];
84
+ }
85
+ /** A vault credential a migration deleted. */
86
+ export interface RemovedCredential {
87
+ vaultId: string;
88
+ credentialId: string;
89
+ /** The URL it was bound to. */
90
+ url: string | null;
77
91
  }
78
92
  /**
79
93
  * Migrates the database, creates its Tenant when it has none, and opens its Session Store.
@@ -4,8 +4,10 @@ import { TenantEnvelopeSchema, } from "@nylorun/core/contracts";
4
4
  import { openError, TenantOpenError } from "../../tenant/cause.js";
5
5
  import { database, driverError } from "./db.js";
6
6
  import { applyMigrations, assertCurrentLayout, isStatementError, lockMigrations, shippedMigrations, } from "./migrate.js";
7
- import { definitions, principals, sessions, signingKeys, TENANT_SCHEMA, tenant, vaults, } from "./schema.js";
7
+ import { definitions, principals, sessions, signingKeys, TENANT_SCHEMA, tenant, vaultAudit, vaults, } from "./schema.js";
8
8
  import { createPostgresSessionStore } from "./store.js";
9
+ /** The migration that deletes the vault's `oauth` credentials, each with an audit row. */
10
+ const OAUTH_REMOVED_MIGRATION = "0016_mcp_oauth_removed";
9
11
  /**
10
12
  * Migrates the database, creates its Tenant when it has none, and opens its Session Store.
11
13
  * Throws a `TenantOpenError` with the cause when the Tenant cannot be opened (see above).
@@ -22,7 +24,8 @@ export async function openTenantDatabase(options) {
22
24
  await assertCurrentLayout(tx);
23
25
  const migrated = await applyMigrations(tx, migrations);
24
26
  const created = await ensureTenant(tx, options.create, migrated, now);
25
- return { created, migrated };
27
+ const removedCredentials = await removedBy(tx, migrations, migrated);
28
+ return { created, migrated, removedCredentials };
26
29
  });
27
30
  }
28
31
  catch (thrown) {
@@ -82,6 +85,23 @@ export async function readTenantEnvelope(q) {
82
85
  throw driverError(error);
83
86
  }
84
87
  }
88
+ /**
89
+ * The credentials `0016_mcp_oauth_removed` deleted, when this transaction applied it: its
90
+ * audit rows (actor `migration`). Empty when it ran before, or is not among `migrations`.
91
+ */
92
+ async function removedBy(tx, migrations, migrated) {
93
+ const index = migrations.findIndex((migration) => migration.tag === OAUTH_REMOVED_MIGRATION);
94
+ if (index < migrated.from || index >= migrated.to)
95
+ return [];
96
+ const rows = await tx
97
+ .select({ vaultId: vaultAudit.vaultId, credentialId: vaultAudit.credentialId, url: vaultAudit.target })
98
+ .from(vaultAudit)
99
+ .where(and(eq(vaultAudit.actor, "migration"), eq(vaultAudit.action, "delete")))
100
+ .orderBy(vaultAudit.ord);
101
+ return rows.flatMap((row) => row.vaultId && row.credentialId
102
+ ? [{ vaultId: row.vaultId, credentialId: row.credentialId, url: row.url }]
103
+ : []);
104
+ }
85
105
  /**
86
106
  * Creates the Tenant when there is none, and adds the principals it is missing. Records the
87
107
  * schema version on the Tenant row when this transaction migrated.