@nylorun/runtime 0.20.0-beta → 0.21.1-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.
- package/CHANGELOG.md +86 -0
- package/README.md +19 -12
- package/dist/adapters/execution/restate.js +26 -1
- package/dist/api/components.d.ts +155 -36
- package/dist/api/components.js +3 -3
- package/dist/api/http/app.js +2 -0
- package/dist/api/http/routes/mcp.d.ts +9 -0
- package/dist/api/http/routes/mcp.js +32 -0
- package/dist/api/http/routes/vaults.d.ts +1 -9
- package/dist/api/http/routes/vaults.js +3 -103
- package/dist/api/openapi.js +6 -3
- package/dist/artifacts/media-types.d.ts +2 -0
- package/dist/artifacts/media-types.js +5 -0
- package/dist/core/flow-host.d.ts +2 -3
- package/dist/core/flow-host.js +10 -7
- package/dist/execution/types.d.ts +13 -5
- package/dist/execution/types.js +13 -5
- package/dist/gates/http-tool.d.ts +7 -0
- package/dist/gates/http-tool.js +34 -3
- package/dist/gates/mcp-handler.d.ts +4 -1
- package/dist/gates/mcp-handler.js +64 -8
- package/dist/gates/tenant-vaults.d.ts +9 -15
- package/dist/gates/tenant-vaults.js +9 -17
- package/dist/gates/tool-client.js +36 -17
- package/dist/gates/tool-contract.d.ts +19 -3
- package/dist/gates/tool-contract.js +9 -3
- package/dist/gates/tool-gate.d.ts +2 -2
- package/dist/harness/calls.d.ts +2 -0
- package/dist/harness/calls.js +13 -3
- package/dist/harness-api/record.d.ts +7 -6
- package/dist/harness-api/record.js +99 -17
- package/dist/harness-api/server.js +35 -27
- package/dist/harness-api/start.js +2 -1
- package/dist/host/config-for.d.ts +0 -2
- package/dist/host/config-for.js +0 -1
- package/dist/host/create-host.d.ts +1 -1
- package/dist/host/create-host.js +2 -1
- package/dist/host/gates.js +0 -1
- package/dist/host/http.d.ts +0 -1
- package/dist/host/http.js +0 -6
- package/dist/host/main.js +13 -3
- package/dist/host/stack-config.d.ts +7 -8
- package/dist/host/stack-config.js +50 -92
- package/dist/index.d.ts +0 -1
- package/dist/keys/client.js +1 -9
- package/dist/keys/keys.d.ts +11 -13
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +315 -345
- package/dist/mcp/connect.d.ts +159 -13
- package/dist/mcp/connect.js +538 -55
- package/dist/mcp/pool.d.ts +11 -2
- package/dist/mcp/pool.js +74 -27
- package/dist/mcp/preview.d.ts +35 -0
- package/dist/mcp/preview.js +215 -0
- package/dist/mcp/snapshot.d.ts +79 -5
- package/dist/mcp/snapshot.js +145 -27
- package/dist/model/catalog.d.ts +14 -0
- package/dist/model/catalog.js +14 -1
- package/dist/model/pi-model.js +36 -2
- package/dist/openapi.json +362 -123
- package/dist/redact.d.ts +19 -1
- package/dist/redact.js +42 -13
- package/dist/sandbox/session-sandbox.d.ts +7 -0
- package/dist/sandbox/session-sandbox.js +89 -28
- package/dist/store/postgres/drizzle/0016_mcp_oauth_removed.sql +5 -0
- package/dist/store/postgres/drizzle/0017_wake_outbox.sql +9 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +14 -0
- package/dist/store/postgres/schema.d.ts +105 -261
- package/dist/store/postgres/schema.js +18 -36
- package/dist/store/postgres/store.js +54 -21
- package/dist/store/postgres/tenant.d.ts +14 -0
- package/dist/store/postgres/tenant.js +22 -2
- package/dist/store/types.d.ts +48 -13
- package/dist/tenant/advance.js +1 -4
- package/dist/tenant/artifact-tool.d.ts +9 -1
- package/dist/tenant/artifact-tool.js +113 -9
- package/dist/tenant/commands.js +5 -5
- package/dist/tenant/context.d.ts +15 -13
- package/dist/tenant/effects.d.ts +2 -2
- package/dist/tenant/effects.js +20 -5
- package/dist/tenant/ephemeral.d.ts +0 -6
- package/dist/tenant/ephemeral.js +0 -1
- package/dist/tenant/outbound.d.ts +14 -5
- package/dist/tenant/outbound.js +21 -9
- package/dist/tenant/runtime.js +11 -15
- package/dist/tenant/sessions.js +20 -3
- package/dist/tenant/store-pg.js +9 -0
- package/dist/tenant/sweep.d.ts +14 -0
- package/dist/tenant/sweep.js +69 -10
- package/dist/tenant/tool-results.d.ts +57 -0
- package/dist/tenant/tool-results.js +298 -0
- package/dist/tenant/tool-search.d.ts +43 -0
- package/dist/tenant/tool-search.js +100 -0
- package/dist/tenant/transcript.d.ts +108 -0
- package/dist/tenant/transcript.js +13 -0
- package/dist/tenant/types.d.ts +0 -14
- package/dist/vault/crypto.d.ts +0 -7
- package/dist/vault/crypto.js +0 -16
- package/dist/vault/headers.d.ts +17 -0
- package/dist/vault/headers.js +61 -0
- package/dist/vault/service.d.ts +11 -68
- package/dist/vault/service.js +83 -438
- package/dist/vault/sources.d.ts +20 -48
- package/dist/vault/sources.js +25 -189
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/vault/oauth.d.ts +0 -55
- 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" | "
|
|
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", "
|
|
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";
|
|
@@ -3598,6 +3340,109 @@ export declare const controlSignals: import("drizzle-orm/pg-core").PgTableWithCo
|
|
|
3598
3340
|
};
|
|
3599
3341
|
dialect: 'pg';
|
|
3600
3342
|
}>;
|
|
3343
|
+
/**
|
|
3344
|
+
* The wake outbox (architecture §12.3): one row per wake a committed transaction asked for
|
|
3345
|
+
* (`Tx.wake`), written in that transaction, so a commit never loses its wake. The row is
|
|
3346
|
+
* deleted once Durable Session Execution has accepted the wake; until then the Tenant sweep
|
|
3347
|
+
* delivers it again, with the same idempotency key (`dedupe_key`, or `wake:<id>` without
|
|
3348
|
+
* one). `created_at` is the insert's own clock (`clock_timestamp()`).
|
|
3349
|
+
*/
|
|
3350
|
+
export declare const wakes: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
3351
|
+
name: "wakes";
|
|
3352
|
+
schema: "nylorun";
|
|
3353
|
+
columns: {
|
|
3354
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
3355
|
+
name: "id";
|
|
3356
|
+
tableName: "wakes";
|
|
3357
|
+
dataType: "custom";
|
|
3358
|
+
columnType: "PgCustomColumn";
|
|
3359
|
+
data: string;
|
|
3360
|
+
driverParam: string;
|
|
3361
|
+
notNull: true;
|
|
3362
|
+
hasDefault: false;
|
|
3363
|
+
isPrimaryKey: true;
|
|
3364
|
+
isAutoincrement: false;
|
|
3365
|
+
hasRuntimeDefault: false;
|
|
3366
|
+
enumValues: undefined;
|
|
3367
|
+
baseColumn: never;
|
|
3368
|
+
identity: undefined;
|
|
3369
|
+
generated: undefined;
|
|
3370
|
+
}, {}, {
|
|
3371
|
+
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
3372
|
+
}>;
|
|
3373
|
+
sessionId: import("drizzle-orm/pg-core").PgColumn<{
|
|
3374
|
+
name: "sessionId";
|
|
3375
|
+
tableName: "wakes";
|
|
3376
|
+
dataType: "custom";
|
|
3377
|
+
columnType: "PgCustomColumn";
|
|
3378
|
+
data: string;
|
|
3379
|
+
driverParam: string;
|
|
3380
|
+
notNull: true;
|
|
3381
|
+
hasDefault: false;
|
|
3382
|
+
isPrimaryKey: false;
|
|
3383
|
+
isAutoincrement: false;
|
|
3384
|
+
hasRuntimeDefault: false;
|
|
3385
|
+
enumValues: undefined;
|
|
3386
|
+
baseColumn: never;
|
|
3387
|
+
identity: undefined;
|
|
3388
|
+
generated: undefined;
|
|
3389
|
+
}, {}, {
|
|
3390
|
+
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
3391
|
+
}>;
|
|
3392
|
+
reason: import("drizzle-orm/pg-core").PgColumn<{
|
|
3393
|
+
name: "reason";
|
|
3394
|
+
tableName: "wakes";
|
|
3395
|
+
dataType: "string";
|
|
3396
|
+
columnType: "PgText";
|
|
3397
|
+
data: string;
|
|
3398
|
+
driverParam: string;
|
|
3399
|
+
notNull: true;
|
|
3400
|
+
hasDefault: false;
|
|
3401
|
+
isPrimaryKey: false;
|
|
3402
|
+
isAutoincrement: false;
|
|
3403
|
+
hasRuntimeDefault: false;
|
|
3404
|
+
enumValues: [string, ...string[]];
|
|
3405
|
+
baseColumn: never;
|
|
3406
|
+
identity: undefined;
|
|
3407
|
+
generated: undefined;
|
|
3408
|
+
}, {}, {}>;
|
|
3409
|
+
dedupeKey: import("drizzle-orm/pg-core").PgColumn<{
|
|
3410
|
+
name: "dedupeKey";
|
|
3411
|
+
tableName: "wakes";
|
|
3412
|
+
dataType: "string";
|
|
3413
|
+
columnType: "PgText";
|
|
3414
|
+
data: string;
|
|
3415
|
+
driverParam: string;
|
|
3416
|
+
notNull: false;
|
|
3417
|
+
hasDefault: false;
|
|
3418
|
+
isPrimaryKey: false;
|
|
3419
|
+
isAutoincrement: false;
|
|
3420
|
+
hasRuntimeDefault: false;
|
|
3421
|
+
enumValues: [string, ...string[]];
|
|
3422
|
+
baseColumn: never;
|
|
3423
|
+
identity: undefined;
|
|
3424
|
+
generated: undefined;
|
|
3425
|
+
}, {}, {}>;
|
|
3426
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
3427
|
+
name: "createdAt";
|
|
3428
|
+
tableName: "wakes";
|
|
3429
|
+
dataType: "date";
|
|
3430
|
+
columnType: "PgTimestamp";
|
|
3431
|
+
data: Date;
|
|
3432
|
+
driverParam: string;
|
|
3433
|
+
notNull: true;
|
|
3434
|
+
hasDefault: true;
|
|
3435
|
+
isPrimaryKey: false;
|
|
3436
|
+
isAutoincrement: false;
|
|
3437
|
+
hasRuntimeDefault: false;
|
|
3438
|
+
enumValues: undefined;
|
|
3439
|
+
baseColumn: never;
|
|
3440
|
+
identity: undefined;
|
|
3441
|
+
generated: undefined;
|
|
3442
|
+
}, {}, {}>;
|
|
3443
|
+
};
|
|
3444
|
+
dialect: 'pg';
|
|
3445
|
+
}>;
|
|
3601
3446
|
/**
|
|
3602
3447
|
* Each sandbox's lifecycle stream (`nylorun.sandbox-event/1`), numbered from 0 per sandbox id.
|
|
3603
3448
|
* Written only by the record module; not published to the stream relay.
|
|
@@ -3924,7 +3769,6 @@ export type VaultRow = typeof vaults.$inferSelect;
|
|
|
3924
3769
|
export type VaultCredentialRow = typeof vaultCredentials.$inferSelect;
|
|
3925
3770
|
export type VaultAuditRow = Omit<typeof vaultAudit.$inferSelect, "ord">;
|
|
3926
3771
|
export type VaultIdempotencyRow = typeof vaultIdempotency.$inferSelect;
|
|
3927
|
-
export type OAuthPendingRow = typeof oauthPending.$inferSelect;
|
|
3928
3772
|
export type SigningKeyRow = typeof signingKeys.$inferSelect;
|
|
3929
3773
|
export type ModelUsageRow = typeof modelUsage.$inferSelect;
|
|
3930
3774
|
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", "
|
|
133
|
-
/** JSON text of the non-secret binding (
|
|
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(),
|
|
@@ -455,6 +421,22 @@ export const controlSignals = nylorun.table("control_signals", {
|
|
|
455
421
|
index("control_signals_created_at").on(t.createdAt),
|
|
456
422
|
check("control_signals_kind_check", sql `${t.kind} IN ('session.cancel', 'sessions.reset')`),
|
|
457
423
|
]);
|
|
424
|
+
/**
|
|
425
|
+
* The wake outbox (architecture §12.3): one row per wake a committed transaction asked for
|
|
426
|
+
* (`Tx.wake`), written in that transaction, so a commit never loses its wake. The row is
|
|
427
|
+
* deleted once Durable Session Execution has accepted the wake; until then the Tenant sweep
|
|
428
|
+
* delivers it again, with the same idempotency key (`dedupe_key`, or `wake:<id>` without
|
|
429
|
+
* one). `created_at` is the insert's own clock (`clock_timestamp()`).
|
|
430
|
+
*/
|
|
431
|
+
export const wakes = nylorun.table("wakes", {
|
|
432
|
+
id: textC().primaryKey(),
|
|
433
|
+
sessionId: textC().notNull(),
|
|
434
|
+
reason: text().notNull(),
|
|
435
|
+
dedupeKey: text(),
|
|
436
|
+
createdAt: timestamp({ withTimezone: true, mode: "date" })
|
|
437
|
+
.notNull()
|
|
438
|
+
.default(sql `clock_timestamp()`),
|
|
439
|
+
}, (t) => [index("wakes_created_at").on(t.createdAt)]);
|
|
458
440
|
// ---------------------------------------------------------------------------
|
|
459
441
|
// nylorun_streams: the record
|
|
460
442
|
/**
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
* `timestamptz`.
|
|
50
50
|
*/
|
|
51
51
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
52
|
+
import { randomUUID } from "node:crypto";
|
|
52
53
|
import { and, count, eq, getTableColumns, gte, inArray, isNotNull, isNull, lt, lte, ne, or, sql, } from "drizzle-orm";
|
|
53
54
|
import { appendEvent, appendSandboxEvent } from "../../record/index.js";
|
|
54
55
|
import { OwnershipLostError, PrincipalRoleConflict } from "../ownership.js";
|
|
@@ -57,7 +58,7 @@ import { database, driverError } from "./db.js";
|
|
|
57
58
|
import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
|
|
58
59
|
import { createPostgresRecordReader } from "./record.js";
|
|
59
60
|
import { postgresRecordWriter, postgresSandboxRecordWriter } from "./record-writer.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,
|
|
61
|
+
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, wakes, } from "./schema.js";
|
|
61
62
|
export function createPostgresSessionStore(options) {
|
|
62
63
|
return new PostgresSessionStore(options);
|
|
63
64
|
}
|
|
@@ -110,7 +111,7 @@ class PostgresSessionStore {
|
|
|
110
111
|
let t;
|
|
111
112
|
// Wrapped so `begin` does not treat an array result as queries to await.
|
|
112
113
|
const run = this.db.transaction(async (db) => {
|
|
113
|
-
t = new PostgresTx(db, this.tenantId, this.now);
|
|
114
|
+
t = new PostgresTx(db, this.tenantId, this.now, this.deleteWake);
|
|
114
115
|
try {
|
|
115
116
|
return { value: await this.active.run(this, () => fn(t)) };
|
|
116
117
|
}
|
|
@@ -153,6 +154,10 @@ class PostgresSessionStore {
|
|
|
153
154
|
}
|
|
154
155
|
return result.value;
|
|
155
156
|
}
|
|
157
|
+
/** Deletes a delivered outbox request, outside any transaction (`Tx.wake`). */
|
|
158
|
+
deleteWake = async (id) => {
|
|
159
|
+
await this.db.delete(wakes).where(eq(wakes.id, id));
|
|
160
|
+
};
|
|
156
161
|
onCommit(listener) {
|
|
157
162
|
this.listeners.add(listener);
|
|
158
163
|
return () => this.listeners.delete(listener);
|
|
@@ -256,21 +261,27 @@ const SIGNING_KEY_STAMP = {
|
|
|
256
261
|
};
|
|
257
262
|
/** The audit columns a row has (`ord` only orders them). */
|
|
258
263
|
const { ord: _ord, ...AUDIT } = getTableColumns(vaultAudit);
|
|
259
|
-
const SESSION_TABLES = [sessions, commands, effects, links];
|
|
264
|
+
const SESSION_TABLES = [sessions, commands, effects, links, wakes];
|
|
265
|
+
/** An outbox row as it is delivered: the wake's own dedupe key, or one made from the row id. */
|
|
266
|
+
function outboxWake(id, reason, dedupeKey) {
|
|
267
|
+
return { reason, dedupeKey: dedupeKey ?? `wake:${id}` };
|
|
268
|
+
}
|
|
260
269
|
/** The inserted row's `column` (`ON CONFLICT … DO UPDATE`). */
|
|
261
270
|
const excluded = (column) => sql.raw(`excluded.${column}`);
|
|
262
271
|
class PostgresTx {
|
|
263
272
|
db;
|
|
264
273
|
tenantId;
|
|
265
274
|
now;
|
|
275
|
+
deleteWake;
|
|
266
276
|
closed = false;
|
|
267
277
|
events = [];
|
|
268
278
|
generations = [];
|
|
269
279
|
callbacks = [];
|
|
270
|
-
constructor(db, tenantId, now) {
|
|
280
|
+
constructor(db, tenantId, now, deleteWake) {
|
|
271
281
|
this.db = db;
|
|
272
282
|
this.tenantId = tenantId;
|
|
273
283
|
this.now = now;
|
|
284
|
+
this.deleteWake = deleteWake;
|
|
274
285
|
}
|
|
275
286
|
check() {
|
|
276
287
|
if (this.closed)
|
|
@@ -345,6 +356,45 @@ class PostgresTx {
|
|
|
345
356
|
this.check();
|
|
346
357
|
this.callbacks.push(fn);
|
|
347
358
|
}
|
|
359
|
+
// --- wake outbox ---------------------------------------------------------
|
|
360
|
+
async wake(sessionId, wake, deliver) {
|
|
361
|
+
this.check();
|
|
362
|
+
const id = randomUUID();
|
|
363
|
+
await this.db.insert(wakes).values({
|
|
364
|
+
id,
|
|
365
|
+
sessionId,
|
|
366
|
+
reason: wake.reason,
|
|
367
|
+
dedupeKey: wake.dedupeKey ?? null,
|
|
368
|
+
});
|
|
369
|
+
const delivered = outboxWake(id, wake.reason, wake.dedupeKey ?? null);
|
|
370
|
+
// A rejection goes to the store's error hook (as every callback's), and the row stays.
|
|
371
|
+
this.callbacks.push(async () => {
|
|
372
|
+
if ((await deliver(sessionId, delivered)) === false)
|
|
373
|
+
return;
|
|
374
|
+
await this.deleteWake(id);
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
async pendingWakes(before, limit) {
|
|
378
|
+
this.check();
|
|
379
|
+
const rows = await this.db
|
|
380
|
+
.select()
|
|
381
|
+
.from(wakes)
|
|
382
|
+
.where(lt(wakes.createdAt, before))
|
|
383
|
+
.orderBy(wakes.createdAt, wakes.id)
|
|
384
|
+
.limit(limit);
|
|
385
|
+
return rows.map((row) => ({
|
|
386
|
+
id: row.id,
|
|
387
|
+
sessionId: row.sessionId,
|
|
388
|
+
wake: outboxWake(row.id, row.reason, row.dedupeKey),
|
|
389
|
+
createdAt: row.createdAt.toISOString(),
|
|
390
|
+
}));
|
|
391
|
+
}
|
|
392
|
+
async deleteWakes(ids) {
|
|
393
|
+
this.check();
|
|
394
|
+
if (ids.length === 0)
|
|
395
|
+
return;
|
|
396
|
+
await this.db.delete(wakes).where(inArray(wakes.id, [...ids]));
|
|
397
|
+
}
|
|
348
398
|
// --- ownership -----------------------------------------------------------
|
|
349
399
|
async takeOwnership(sessionId, claim) {
|
|
350
400
|
this.check();
|
|
@@ -765,23 +815,6 @@ class PostgresTx {
|
|
|
765
815
|
this.check();
|
|
766
816
|
await this.db.insert(vaultIdempotency).values(row);
|
|
767
817
|
}
|
|
768
|
-
async insertOAuthPending(row) {
|
|
769
|
-
this.check();
|
|
770
|
-
await this.db.insert(oauthPending).values(row);
|
|
771
|
-
}
|
|
772
|
-
async takeOAuthPending(stateHash) {
|
|
773
|
-
this.check();
|
|
774
|
-
const [row] = await this.db
|
|
775
|
-
.delete(oauthPending)
|
|
776
|
-
.where(eq(oauthPending.stateHash, stateHash))
|
|
777
|
-
.returning();
|
|
778
|
-
return row;
|
|
779
|
-
}
|
|
780
|
-
async deleteExpiredOAuthPending(now) {
|
|
781
|
-
this.check();
|
|
782
|
-
const result = await this.db.delete(oauthPending).where(lt(oauthPending.expiresAt, now));
|
|
783
|
-
return result.count;
|
|
784
|
-
}
|
|
785
818
|
// --- signing keys --------------------------------------------------------
|
|
786
819
|
async lockSigningKeys() {
|
|
787
820
|
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
|
-
|
|
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.
|