@hasna/instructions 0.4.35 → 0.4.39
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/README.md +4 -2
- package/assets/skills/inbox/SKILL.md +86 -0
- package/dashboard/README.md +34 -70
- package/dist/cli/index.js +1136 -526
- package/dist/cli/raw-store-root.test.d.ts +2 -0
- package/dist/cli/raw-store-root.test.d.ts.map +1 -0
- package/dist/db/configs.d.ts.map +1 -1
- package/dist/generated/storage-kit/index.d.ts +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1276 -754
- package/dist/lib/apply.d.ts.map +1 -1
- package/dist/lib/cursor-authority.d.ts +36 -3
- package/dist/lib/cursor-authority.d.ts.map +1 -1
- package/dist/lib/managed-skill-runtimes.d.ts +80 -0
- package/dist/lib/managed-skill-runtimes.d.ts.map +1 -0
- package/dist/lib/managed-skill-runtimes.test.d.ts +2 -0
- package/dist/lib/managed-skill-runtimes.test.d.ts.map +1 -0
- package/dist/lib/raw-store-root.d.ts +17 -0
- package/dist/lib/raw-store-root.d.ts.map +1 -0
- package/dist/lib/session-apply.d.ts.map +1 -1
- package/dist/lib/session-authority.d.ts +27 -0
- package/dist/lib/session-authority.d.ts.map +1 -0
- package/dist/lib/session-authority.test.d.ts +2 -0
- package/dist/lib/session-authority.test.d.ts.map +1 -0
- package/dist/lib/session-render.d.ts +5 -3
- package/dist/lib/session-render.d.ts.map +1 -1
- package/dist/mcp/index.js +290 -233
- package/dist/server/index.js +425 -231
- package/dist/status.d.ts +11 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/storage/cloud-store.d.ts.map +1 -1
- package/dist/storage/cloud-store.test.d.ts +2 -0
- package/dist/storage/cloud-store.test.d.ts.map +1 -0
- package/package.json +9 -7
package/dist/server/index.js
CHANGED
|
@@ -1258,78 +1258,6 @@ var RegExpRouter = class {
|
|
|
1258
1258
|
}
|
|
1259
1259
|
};
|
|
1260
1260
|
|
|
1261
|
-
// ../../node_modules/.bun/hono@4.13.1/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
|
|
1262
|
-
var PreparedRegExpRouter = class {
|
|
1263
|
-
name = "PreparedRegExpRouter";
|
|
1264
|
-
#matchers;
|
|
1265
|
-
#relocateMap;
|
|
1266
|
-
constructor(matchers, relocateMap) {
|
|
1267
|
-
this.#matchers = matchers;
|
|
1268
|
-
this.#relocateMap = relocateMap;
|
|
1269
|
-
}
|
|
1270
|
-
#addWildcard(method, handlerData) {
|
|
1271
|
-
const matcher = this.#matchers[method];
|
|
1272
|
-
matcher[1].forEach((list) => list && list.push(handlerData));
|
|
1273
|
-
Object.values(matcher[2]).forEach((list) => list[0].push(handlerData));
|
|
1274
|
-
}
|
|
1275
|
-
#addPath(method, path, handler, indexes, map) {
|
|
1276
|
-
const matcher = this.#matchers[method];
|
|
1277
|
-
if (!map) {
|
|
1278
|
-
matcher[2][path][0].push([handler, {}]);
|
|
1279
|
-
} else {
|
|
1280
|
-
indexes.forEach((index) => {
|
|
1281
|
-
if (typeof index === "number") {
|
|
1282
|
-
matcher[1][index].push([handler, map]);
|
|
1283
|
-
} else {
|
|
1284
|
-
matcher[2][index || path][0].push([handler, map]);
|
|
1285
|
-
}
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
add(method, path, handler) {
|
|
1290
|
-
if (!this.#matchers[method]) {
|
|
1291
|
-
const all = this.#matchers[METHOD_NAME_ALL];
|
|
1292
|
-
const staticMap = {};
|
|
1293
|
-
for (const key in all[2]) {
|
|
1294
|
-
staticMap[key] = [all[2][key][0].slice(), emptyParam];
|
|
1295
|
-
}
|
|
1296
|
-
this.#matchers[method] = [
|
|
1297
|
-
all[0],
|
|
1298
|
-
all[1].map((list) => Array.isArray(list) ? list.slice() : 0),
|
|
1299
|
-
staticMap
|
|
1300
|
-
];
|
|
1301
|
-
}
|
|
1302
|
-
if (path === "/*" || path === "*") {
|
|
1303
|
-
const handlerData = [handler, {}];
|
|
1304
|
-
if (method === METHOD_NAME_ALL) {
|
|
1305
|
-
for (const m in this.#matchers) {
|
|
1306
|
-
this.#addWildcard(m, handlerData);
|
|
1307
|
-
}
|
|
1308
|
-
} else {
|
|
1309
|
-
this.#addWildcard(method, handlerData);
|
|
1310
|
-
}
|
|
1311
|
-
return;
|
|
1312
|
-
}
|
|
1313
|
-
const data = this.#relocateMap[path];
|
|
1314
|
-
if (!data) {
|
|
1315
|
-
throw new Error(`Path ${path} is not registered`);
|
|
1316
|
-
}
|
|
1317
|
-
for (const [indexes, map] of data) {
|
|
1318
|
-
if (method === METHOD_NAME_ALL) {
|
|
1319
|
-
for (const m in this.#matchers) {
|
|
1320
|
-
this.#addPath(m, path, handler, indexes, map);
|
|
1321
|
-
}
|
|
1322
|
-
} else {
|
|
1323
|
-
this.#addPath(method, path, handler, indexes, map);
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
buildAllMatchers() {
|
|
1328
|
-
return this.#matchers;
|
|
1329
|
-
}
|
|
1330
|
-
match = match;
|
|
1331
|
-
};
|
|
1332
|
-
|
|
1333
1261
|
// ../../node_modules/.bun/hono@4.13.1/node_modules/hono/dist/router/smart-router/router.js
|
|
1334
1262
|
var SmartRouter = class {
|
|
1335
1263
|
name = "SmartRouter";
|
|
@@ -1744,14 +1672,90 @@ class ProfileNotFoundError extends Error {
|
|
|
1744
1672
|
}
|
|
1745
1673
|
}
|
|
1746
1674
|
|
|
1747
|
-
//
|
|
1675
|
+
// ../contracts/dist/auth/index.js
|
|
1748
1676
|
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
1677
|
+
var MAX_TENANT_ID_LENGTH = 64;
|
|
1678
|
+
var TENANT_ID_PATTERN = new RegExp(`^[A-Za-z0-9][A-Za-z0-9._-]{0,${MAX_TENANT_ID_LENGTH - 1}}$`);
|
|
1679
|
+
var UUID_HEX = "[0-9a-fA-F]";
|
|
1680
|
+
var UUID_PATTERN = new RegExp(`^\\{?(?:${UUID_HEX}{8}-${UUID_HEX}{4}-${UUID_HEX}{4}-${UUID_HEX}{4}-${UUID_HEX}{12}|${UUID_HEX}{32})\\}?$`);
|
|
1681
|
+
function isValidTenantId(value) {
|
|
1682
|
+
return typeof value === "string" && TENANT_ID_PATTERN.test(value);
|
|
1683
|
+
}
|
|
1684
|
+
function isUuidTenantId(value) {
|
|
1685
|
+
return typeof value === "string" && UUID_PATTERN.test(value);
|
|
1686
|
+
}
|
|
1687
|
+
function canonicalizeTenantId(value) {
|
|
1688
|
+
if (!isUuidTenantId(value))
|
|
1689
|
+
return value;
|
|
1690
|
+
const hex = value.replace(/[{}-]/g, "").toLowerCase();
|
|
1691
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
1692
|
+
}
|
|
1693
|
+
function normalizeTenantId(value) {
|
|
1694
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
1695
|
+
const canonical = canonicalizeTenantId(trimmed);
|
|
1696
|
+
if (!isValidTenantId(canonical)) {
|
|
1697
|
+
throw new Error(`Invalid tenant id '${value}'. Expected 1-${MAX_TENANT_ID_LENGTH} characters matching ${TENANT_ID_PATTERN} (a UUID, ULID, slug, or prefixed id).`);
|
|
1698
|
+
}
|
|
1699
|
+
return canonical;
|
|
1700
|
+
}
|
|
1701
|
+
function tenantIdsEqual(left, right) {
|
|
1702
|
+
const canonical = (value) => {
|
|
1703
|
+
if (typeof value !== "string")
|
|
1704
|
+
return null;
|
|
1705
|
+
const folded = canonicalizeTenantId(value.trim());
|
|
1706
|
+
return isValidTenantId(folded) ? folded : null;
|
|
1707
|
+
};
|
|
1708
|
+
const a = canonical(left);
|
|
1709
|
+
const b = canonical(right);
|
|
1710
|
+
return a !== null && b !== null && a === b;
|
|
1711
|
+
}
|
|
1712
|
+
function ownTenantId(source) {
|
|
1713
|
+
return Object.hasOwn(source, "tid") ? source.tid : undefined;
|
|
1714
|
+
}
|
|
1749
1715
|
var API_KEY_TOKEN_VERSION = 1;
|
|
1750
1716
|
var API_KEY_NAMESPACE = "hasna";
|
|
1751
|
-
var
|
|
1717
|
+
var API_KEY_TOKEN_PATTERN = /^hasna_([a-z][a-z0-9-]*)_([A-Za-z0-9_-]+)\.([A-Za-z0-9_-]+)$/;
|
|
1718
|
+
var TOKEN_PATTERN = API_KEY_TOKEN_PATTERN;
|
|
1752
1719
|
var DEFAULT_API_KEY_TTL_SECONDS = 90 * 24 * 60 * 60;
|
|
1720
|
+
function ownAgentClaim(source) {
|
|
1721
|
+
return Object.hasOwn(source, "agent") && typeof source.agent === "string" ? source.agent : null;
|
|
1722
|
+
}
|
|
1723
|
+
function ownScopesClaim(source) {
|
|
1724
|
+
return Object.hasOwn(source, "scopes") && Array.isArray(source.scopes) ? source.scopes : null;
|
|
1725
|
+
}
|
|
1726
|
+
function ownOption(options, name) {
|
|
1727
|
+
return Object.hasOwn(options, name) ? options[name] : undefined;
|
|
1728
|
+
}
|
|
1729
|
+
var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
1730
|
+
var intrinsicViewBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
|
|
1731
|
+
var intrinsicViewByteOffset = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset").get;
|
|
1732
|
+
var intrinsicViewByteLength = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength").get;
|
|
1733
|
+
var intrinsicDataViewBuffer = Object.getOwnPropertyDescriptor(DataView.prototype, "buffer").get;
|
|
1734
|
+
var intrinsicDataViewByteOffset = Object.getOwnPropertyDescriptor(DataView.prototype, "byteOffset").get;
|
|
1735
|
+
var intrinsicDataViewByteLength = Object.getOwnPropertyDescriptor(DataView.prototype, "byteLength").get;
|
|
1736
|
+
function viewWindow(view) {
|
|
1737
|
+
try {
|
|
1738
|
+
return [
|
|
1739
|
+
intrinsicViewBuffer.call(view),
|
|
1740
|
+
intrinsicViewByteOffset.call(view),
|
|
1741
|
+
intrinsicViewByteLength.call(view)
|
|
1742
|
+
];
|
|
1743
|
+
} catch {
|
|
1744
|
+
return [
|
|
1745
|
+
intrinsicDataViewBuffer.call(view),
|
|
1746
|
+
intrinsicDataViewByteOffset.call(view),
|
|
1747
|
+
intrinsicDataViewByteLength.call(view)
|
|
1748
|
+
];
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1753
1751
|
function toBuffer(secret) {
|
|
1754
|
-
|
|
1752
|
+
if (typeof secret === "string")
|
|
1753
|
+
return Buffer.from(secret, "utf8");
|
|
1754
|
+
if (ArrayBuffer.isView(secret)) {
|
|
1755
|
+
const [store, byteOffset, byteLength] = viewWindow(secret);
|
|
1756
|
+
return Buffer.from(store, byteOffset, byteLength);
|
|
1757
|
+
}
|
|
1758
|
+
return Buffer.from(secret);
|
|
1755
1759
|
}
|
|
1756
1760
|
function hmac(signingSecret, message) {
|
|
1757
1761
|
return createHmac("sha256", toBuffer(signingSecret)).update(message, "utf8").digest();
|
|
@@ -1774,12 +1778,23 @@ function parseApiKey(token) {
|
|
|
1774
1778
|
} catch {
|
|
1775
1779
|
return null;
|
|
1776
1780
|
}
|
|
1777
|
-
if (typeof claims !== "object" || claims === null || typeof claims.kid !== "string" || typeof claims.app !== "string" ||
|
|
1781
|
+
if (typeof claims !== "object" || claims === null || typeof claims.kid !== "string" || typeof claims.app !== "string" || ownScopesClaim(claims) === null) {
|
|
1782
|
+
return null;
|
|
1783
|
+
}
|
|
1784
|
+
const claimedTid = ownTenantId(claims);
|
|
1785
|
+
if (claimedTid !== undefined && !isValidTenantId(claimedTid)) {
|
|
1778
1786
|
return null;
|
|
1779
1787
|
}
|
|
1780
1788
|
return { app, body, sig, claims };
|
|
1781
1789
|
}
|
|
1782
1790
|
function verifyApiKeyToken(token, options) {
|
|
1791
|
+
const optSigningSecret = ownOption(options, "signingSecret");
|
|
1792
|
+
const optExpectedApp = ownOption(options, "expectedApp");
|
|
1793
|
+
const optNowMs = ownOption(options, "nowMs");
|
|
1794
|
+
const optLeewaySeconds = ownOption(options, "leewaySeconds");
|
|
1795
|
+
const optRequiredScopes = ownOption(options, "requiredScopes");
|
|
1796
|
+
const optRequireTenant = ownOption(options, "requireTenant");
|
|
1797
|
+
const optExpectedTid = ownOption(options, "expectedTid");
|
|
1783
1798
|
const parsed = parseApiKey(token);
|
|
1784
1799
|
if (!parsed) {
|
|
1785
1800
|
return { ok: false, reason: "malformed", message: "Token is malformed." };
|
|
@@ -1791,10 +1806,10 @@ function verifyApiKeyToken(token, options) {
|
|
|
1791
1806
|
if (claims.app !== app) {
|
|
1792
1807
|
return { ok: false, reason: "app_mismatch", message: "Token prefix app does not match claims." };
|
|
1793
1808
|
}
|
|
1794
|
-
if (
|
|
1795
|
-
return { ok: false, reason: "app_mismatch", message: `Token is for app '${app}', expected '${
|
|
1809
|
+
if (optExpectedApp !== undefined && app !== optExpectedApp) {
|
|
1810
|
+
return { ok: false, reason: "app_mismatch", message: `Token is for app '${app}', expected '${optExpectedApp}'.` };
|
|
1796
1811
|
}
|
|
1797
|
-
const expected = hmac(
|
|
1812
|
+
const expected = hmac(optSigningSecret, `${apiKeyPrefix(app)}${body}`);
|
|
1798
1813
|
let provided;
|
|
1799
1814
|
try {
|
|
1800
1815
|
provided = Buffer.from(sig, "base64url");
|
|
@@ -1804,16 +1819,41 @@ function verifyApiKeyToken(token, options) {
|
|
|
1804
1819
|
if (provided.length !== expected.length || !timingSafeEqual(provided, expected)) {
|
|
1805
1820
|
return { ok: false, reason: "bad_signature", message: "Signature verification failed." };
|
|
1806
1821
|
}
|
|
1807
|
-
const
|
|
1808
|
-
const
|
|
1822
|
+
const agent = ownAgentClaim(claims);
|
|
1823
|
+
const now = Math.floor((optNowMs ?? Date.now()) / 1000);
|
|
1824
|
+
const leeway = optLeewaySeconds ?? 0;
|
|
1809
1825
|
if (typeof claims.iat === "number" && now + leeway < claims.iat) {
|
|
1810
|
-
return { ok: false, reason: "not_yet_valid", message: "Token is not yet valid." };
|
|
1826
|
+
return { ok: false, reason: "not_yet_valid", message: "Token is not yet valid.", agent };
|
|
1811
1827
|
}
|
|
1812
1828
|
if (claims.exp !== null && typeof claims.exp === "number" && now - leeway >= claims.exp) {
|
|
1813
|
-
return { ok: false, reason: "expired", message: "Token has expired." };
|
|
1829
|
+
return { ok: false, reason: "expired", message: "Token has expired.", agent };
|
|
1830
|
+
}
|
|
1831
|
+
const verifiedTid = ownTenantId(claims);
|
|
1832
|
+
const tid = verifiedTid === undefined ? null : canonicalizeTenantId(verifiedTid);
|
|
1833
|
+
const tenantRequired = Boolean(optRequireTenant) || optExpectedTid !== undefined;
|
|
1834
|
+
if (tenantRequired && tid === null) {
|
|
1835
|
+
return {
|
|
1836
|
+
ok: false,
|
|
1837
|
+
reason: "tenant_required",
|
|
1838
|
+
message: "Token carries no tenant id ('tid') and this service requires one.",
|
|
1839
|
+
kid: claims.kid,
|
|
1840
|
+
tid: null,
|
|
1841
|
+
agent
|
|
1842
|
+
};
|
|
1814
1843
|
}
|
|
1815
|
-
if (
|
|
1816
|
-
const
|
|
1844
|
+
if (optExpectedTid !== undefined && !tenantIdsEqual(tid, optExpectedTid)) {
|
|
1845
|
+
const expectationIsWellFormed = typeof optExpectedTid === "string" && isValidTenantId(optExpectedTid.trim());
|
|
1846
|
+
return {
|
|
1847
|
+
ok: false,
|
|
1848
|
+
reason: "tenant_mismatch",
|
|
1849
|
+
message: expectationIsWellFormed ? "Token is for a different tenant than the one this service accepts." : "Token tenant cannot be checked: the expected tenant id is not a valid tenant id.",
|
|
1850
|
+
kid: claims.kid,
|
|
1851
|
+
tid,
|
|
1852
|
+
agent
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1855
|
+
if (optRequiredScopes && optRequiredScopes.length > 0) {
|
|
1856
|
+
const granted = ownScopesClaim(claims) ?? [];
|
|
1817
1857
|
const satisfies = (required) => granted.some((g) => {
|
|
1818
1858
|
if (g === "*")
|
|
1819
1859
|
return true;
|
|
@@ -1827,15 +1867,16 @@ function verifyApiKeyToken(token, options) {
|
|
|
1827
1867
|
const rAction = required.slice(ri + 1);
|
|
1828
1868
|
return (gApp === "*" || gApp === rApp) && (gAction === "*" || gAction === rAction);
|
|
1829
1869
|
});
|
|
1830
|
-
for (const required of
|
|
1870
|
+
for (const required of optRequiredScopes) {
|
|
1831
1871
|
if (!satisfies(required)) {
|
|
1832
|
-
return { ok: false, reason: "insufficient_scope", message: `Missing required scope '${required}'
|
|
1872
|
+
return { ok: false, reason: "insufficient_scope", message: `Missing required scope '${required}'.`, agent };
|
|
1833
1873
|
}
|
|
1834
1874
|
}
|
|
1835
1875
|
}
|
|
1836
|
-
return { ok: true, claims, kid: claims.kid, app };
|
|
1876
|
+
return { ok: true, claims, kid: claims.kid, app, tid, agent };
|
|
1837
1877
|
}
|
|
1838
1878
|
var DEFAULT_API_KEYS_TABLE = "api_keys";
|
|
1879
|
+
var API_KEY_ISSUANCE_PENDING_REASON = "credential_delivery_pending";
|
|
1839
1880
|
function createTableSql(table) {
|
|
1840
1881
|
return `CREATE TABLE IF NOT EXISTS ${table} (
|
|
1841
1882
|
kid TEXT PRIMARY KEY,
|
|
@@ -1859,6 +1900,11 @@ function apiKeyMigrations(table = DEFAULT_API_KEYS_TABLE) {
|
|
|
1859
1900
|
id: `hasna_auth_0002_${table}_indexes`,
|
|
1860
1901
|
sql: `CREATE INDEX IF NOT EXISTS ${table}_app_idx ON ${table} (app);
|
|
1861
1902
|
CREATE INDEX IF NOT EXISTS ${table}_token_hash_idx ON ${table} (token_hash);`
|
|
1903
|
+
},
|
|
1904
|
+
{
|
|
1905
|
+
id: `hasna_auth_0003_${table}_tenant`,
|
|
1906
|
+
sql: `ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS tid TEXT;
|
|
1907
|
+
CREATE INDEX IF NOT EXISTS ${table}_tid_idx ON ${table} (tid);`
|
|
1862
1908
|
}
|
|
1863
1909
|
];
|
|
1864
1910
|
}
|
|
@@ -1883,10 +1929,13 @@ function parseScopes(value) {
|
|
|
1883
1929
|
return [];
|
|
1884
1930
|
}
|
|
1885
1931
|
function rowToRecord(row) {
|
|
1932
|
+
const tid = ownTenantId(row);
|
|
1933
|
+
const agentValue = Object.hasOwn(row, "agent") ? row.agent : null;
|
|
1886
1934
|
return {
|
|
1887
1935
|
kid: String(row.kid),
|
|
1888
1936
|
app: String(row.app),
|
|
1889
|
-
agent:
|
|
1937
|
+
agent: agentValue === null || agentValue === undefined ? null : String(agentValue),
|
|
1938
|
+
tid: tid === null || tid === undefined ? null : String(tid),
|
|
1890
1939
|
scopes: parseScopes(row.scopes),
|
|
1891
1940
|
tokenHash: String(row.token_hash),
|
|
1892
1941
|
issuedAt: toIso(row.issued_at) ?? new Date(0).toISOString(),
|
|
@@ -1917,31 +1966,63 @@ class ApiKeyStore {
|
|
|
1917
1966
|
}
|
|
1918
1967
|
}
|
|
1919
1968
|
async insert(input) {
|
|
1969
|
+
await this.insertWithLifecycle(input, null, null);
|
|
1970
|
+
}
|
|
1971
|
+
async insertWithLifecycle(input, revokedAt, revokedReason) {
|
|
1972
|
+
const tid = ownTenantId(input);
|
|
1973
|
+
const agent = ownAgentClaim(input);
|
|
1920
1974
|
await this.client.execute(`INSERT INTO ${this.table}
|
|
1921
|
-
(kid, app, agent, scopes, token_hash, issued_at, expires_at, created_by)
|
|
1922
|
-
VALUES ($1, $2, $3, $4
|
|
1975
|
+
(kid, app, agent, tid, scopes, token_hash, issued_at, expires_at, created_by, revoked_at, revoked_reason)
|
|
1976
|
+
VALUES ($1, $2, $3, $4, $5::jsonb, $6, $7, $8, $9, $10, $11)`, [
|
|
1923
1977
|
input.kid,
|
|
1924
1978
|
input.app,
|
|
1925
|
-
|
|
1979
|
+
agent,
|
|
1980
|
+
tid === undefined || tid === null ? null : normalizeTenantId(tid),
|
|
1926
1981
|
JSON.stringify(input.scopes),
|
|
1927
1982
|
input.tokenHash,
|
|
1928
1983
|
input.issuedAt.toISOString(),
|
|
1929
1984
|
input.expiresAt ? input.expiresAt.toISOString() : null,
|
|
1930
|
-
input.createdBy ?? null
|
|
1985
|
+
input.createdBy ?? null,
|
|
1986
|
+
revokedAt,
|
|
1987
|
+
revokedReason
|
|
1931
1988
|
]);
|
|
1932
1989
|
}
|
|
1933
|
-
|
|
1990
|
+
mintedInput(minted, createdBy) {
|
|
1934
1991
|
const claims = minted.claims;
|
|
1935
|
-
|
|
1992
|
+
return {
|
|
1936
1993
|
kid: minted.kid,
|
|
1937
1994
|
app: claims.app,
|
|
1938
|
-
agent: claims
|
|
1995
|
+
agent: ownAgentClaim(claims),
|
|
1996
|
+
tid: ownTenantId(claims) ?? null,
|
|
1939
1997
|
scopes: claims.scopes,
|
|
1940
1998
|
tokenHash: minted.tokenHash,
|
|
1941
1999
|
issuedAt: new Date(claims.iat * 1000),
|
|
1942
2000
|
expiresAt: claims.exp === null ? null : new Date(claims.exp * 1000),
|
|
1943
2001
|
createdBy: createdBy ?? null
|
|
1944
|
-
}
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
async insertMinted(minted, createdBy) {
|
|
2005
|
+
await this.insert(this.mintedInput(minted, createdBy));
|
|
2006
|
+
}
|
|
2007
|
+
async insertMintedPending(minted, createdBy, atMs = Date.now()) {
|
|
2008
|
+
await this.insertWithLifecycle(this.mintedInput(minted, createdBy), new Date(atMs).toISOString(), API_KEY_ISSUANCE_PENDING_REASON);
|
|
2009
|
+
}
|
|
2010
|
+
async activatePending(kid, tokenHash) {
|
|
2011
|
+
const row = await this.client.get(`UPDATE ${this.table}
|
|
2012
|
+
SET revoked_at = NULL, revoked_reason = NULL
|
|
2013
|
+
WHERE kid = $1
|
|
2014
|
+
AND revoked_at IS NOT NULL
|
|
2015
|
+
AND revoked_reason = $2
|
|
2016
|
+
AND token_hash = $3
|
|
2017
|
+
RETURNING kid`, [kid, API_KEY_ISSUANCE_PENDING_REASON, tokenHash]);
|
|
2018
|
+
if (row)
|
|
2019
|
+
return true;
|
|
2020
|
+
const active = await this.client.get(`SELECT kid FROM ${this.table}
|
|
2021
|
+
WHERE kid = $1
|
|
2022
|
+
AND token_hash = $2
|
|
2023
|
+
AND revoked_at IS NULL
|
|
2024
|
+
AND revoked_reason IS NULL`, [kid, tokenHash]);
|
|
2025
|
+
return active !== null;
|
|
1945
2026
|
}
|
|
1946
2027
|
async findByKid(kid) {
|
|
1947
2028
|
const row = await this.client.get(`SELECT * FROM ${this.table} WHERE kid = $1`, [kid]);
|
|
@@ -1967,6 +2048,9 @@ class ApiKeyStore {
|
|
|
1967
2048
|
return "expired";
|
|
1968
2049
|
return "active";
|
|
1969
2050
|
}
|
|
2051
|
+
keyStatus = async (kid) => {
|
|
2052
|
+
return this.status(kid);
|
|
2053
|
+
};
|
|
1970
2054
|
statusChecker() {
|
|
1971
2055
|
return async (kid) => {
|
|
1972
2056
|
const status = await this.status(kid);
|
|
@@ -1993,11 +2077,16 @@ class ApiKeyStore {
|
|
|
1993
2077
|
params.push(options.app);
|
|
1994
2078
|
clauses.push(`app = $${params.length}`);
|
|
1995
2079
|
}
|
|
2080
|
+
const tid = ownTenantId(options);
|
|
2081
|
+
if (tid !== undefined) {
|
|
2082
|
+
params.push(normalizeTenantId(tid));
|
|
2083
|
+
clauses.push(`tid = $${params.length}`);
|
|
2084
|
+
}
|
|
1996
2085
|
if (!options.includeRevoked) {
|
|
1997
2086
|
clauses.push("revoked_at IS NULL");
|
|
1998
2087
|
}
|
|
1999
2088
|
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
2000
|
-
const rows = await this.client.many(`SELECT * FROM ${this.table} ${where} ORDER BY issued_at DESC
|
|
2089
|
+
const rows = await this.client.many(`SELECT * FROM ${this.table} ${where} ORDER BY issued_at DESC`, params);
|
|
2001
2090
|
return rows.map(rowToRecord);
|
|
2002
2091
|
}
|
|
2003
2092
|
async revokedKids() {
|
|
@@ -2034,27 +2123,65 @@ function extractToken(source, headerName = "x-api-key", scheme = "Bearer") {
|
|
|
2034
2123
|
}
|
|
2035
2124
|
return null;
|
|
2036
2125
|
}
|
|
2126
|
+
function ownOption2(bag, name) {
|
|
2127
|
+
return Object.hasOwn(bag, name) ? bag[name] : undefined;
|
|
2128
|
+
}
|
|
2037
2129
|
function verifyApiKey(options) {
|
|
2038
|
-
|
|
2130
|
+
const optionApp = ownOption2(options, "app");
|
|
2131
|
+
const optionSigningSecret = ownOption2(options, "signingSecret");
|
|
2132
|
+
const optionExpectedTid = ownOption2(options, "expectedTid");
|
|
2133
|
+
const optionRequiredScopes = ownOption2(options, "requiredScopes");
|
|
2134
|
+
const optionRequireTenant = ownOption2(options, "requireTenant");
|
|
2135
|
+
const optionLeewaySeconds = ownOption2(options, "leewaySeconds");
|
|
2136
|
+
const audit = ownOption2(options, "audit");
|
|
2137
|
+
const headerName = ownOption2(options, "headerName") ?? "x-api-key";
|
|
2138
|
+
const scheme = ownOption2(options, "scheme") ?? "Bearer";
|
|
2139
|
+
const clock = ownOption2(options, "nowMs") ?? (() => Date.now());
|
|
2140
|
+
if (!optionApp)
|
|
2039
2141
|
throw new Error("verifyApiKey requires an 'app' slug.");
|
|
2040
|
-
if (!
|
|
2142
|
+
if (!optionSigningSecret) {
|
|
2041
2143
|
throw new Error("verifyApiKey requires a 'signingSecret'. Set it from HASNA_<APP>_API_SIGNING_KEY.");
|
|
2042
2144
|
}
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2145
|
+
if (optionExpectedTid !== undefined && !isValidTenantId(optionExpectedTid)) {
|
|
2146
|
+
throw new Error(`verifyApiKey received an invalid 'expectedTid': '${optionExpectedTid}'.`);
|
|
2147
|
+
}
|
|
2148
|
+
const app = optionApp;
|
|
2149
|
+
const signingSecret = optionSigningSecret;
|
|
2150
|
+
const ownKeyStatus = ownOption2(options, "keyStatus");
|
|
2151
|
+
const ownIsRevoked = ownOption2(options, "isRevoked");
|
|
2152
|
+
const allowUnregistered = ownOption2(options, "allowUnregisteredKeys") === true;
|
|
2153
|
+
if (ownKeyStatus && ownIsRevoked) {
|
|
2154
|
+
throw new Error("verifyApiKey received both 'keyStatus' and 'isRevoked'. Supply exactly one \u2014 " + "letting one silently win would hide which check is actually guarding the service. " + "Use 'keyStatus' (store.keyStatus); drop 'isRevoked'.");
|
|
2155
|
+
}
|
|
2156
|
+
if (!ownKeyStatus && !allowUnregistered) {
|
|
2157
|
+
throw new Error(ownIsRevoked ? "verifyApiKey was given only 'isRevoked', which cannot refuse a key this service has " + "no record of: it returns false both for an active key and for one that was never " + "registered, so an unregistered key is irrevocable. Wire 'keyStatus: store.keyStatus' " + "(or 'isRevoked: store.statusChecker()'), or set 'allowUnregisteredKeys: true' to " + "accept that risk explicitly." : "verifyApiKey requires a key-status hook. Without one this service performs NO " + "revocation check and cannot turn any of its keys off. Wire " + "'keyStatus: store.keyStatus', or set 'allowUnregisteredKeys: true' to declare that " + "this service intentionally cannot revoke keys.");
|
|
2158
|
+
}
|
|
2046
2159
|
async function emit(event) {
|
|
2047
|
-
if (!
|
|
2160
|
+
if (!audit)
|
|
2048
2161
|
return;
|
|
2049
2162
|
try {
|
|
2050
|
-
await
|
|
2163
|
+
await audit(event);
|
|
2051
2164
|
} catch {}
|
|
2052
2165
|
}
|
|
2053
2166
|
async function authenticate(headers, context = {}) {
|
|
2054
|
-
const method = context
|
|
2055
|
-
const path = context
|
|
2056
|
-
const requiredScopes = [
|
|
2167
|
+
const method = ownOption2(context, "method") ?? null;
|
|
2168
|
+
const path = ownOption2(context, "path") ?? null;
|
|
2169
|
+
const requiredScopes = [
|
|
2170
|
+
...optionRequiredScopes ?? [],
|
|
2171
|
+
...ownOption2(context, "requiredScopes") ?? []
|
|
2172
|
+
];
|
|
2057
2173
|
const at = new Date(clock()).toISOString();
|
|
2174
|
+
const perCallTid = ownOption2(context, "expectedTid");
|
|
2175
|
+
const expectedTid = perCallTid !== undefined ? perCallTid : optionExpectedTid;
|
|
2176
|
+
if (perCallTid !== undefined && optionExpectedTid !== undefined && !tenantIdsEqual(perCallTid, optionExpectedTid)) {
|
|
2177
|
+
await emit({ outcome: "deny", app, kid: null, tid: null, reason: "tenant_mismatch", scopesRequired: requiredScopes, method, path, status: 403, at });
|
|
2178
|
+
return {
|
|
2179
|
+
ok: false,
|
|
2180
|
+
status: 403,
|
|
2181
|
+
reason: "tenant_mismatch",
|
|
2182
|
+
message: "This route addresses a tenant other than the one this service is pinned to."
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2058
2185
|
const token = extractToken(headers, headerName, scheme);
|
|
2059
2186
|
if (!token) {
|
|
2060
2187
|
const decision = {
|
|
@@ -2063,25 +2190,72 @@ function verifyApiKey(options) {
|
|
|
2063
2190
|
reason: "missing_token",
|
|
2064
2191
|
message: `Missing API key. Send it as '${headerName}: <key>' or 'Authorization: ${scheme} <key>'.`
|
|
2065
2192
|
};
|
|
2066
|
-
await emit({ outcome: "deny", app:
|
|
2193
|
+
await emit({ outcome: "deny", app, kid: null, tid: null, reason: "missing_token", scopesRequired: requiredScopes, method, path, status: 401, at });
|
|
2067
2194
|
return decision;
|
|
2068
2195
|
}
|
|
2069
2196
|
const verified = verifyApiKeyToken(token, {
|
|
2070
|
-
signingSecret
|
|
2071
|
-
expectedApp:
|
|
2197
|
+
signingSecret,
|
|
2198
|
+
expectedApp: app,
|
|
2072
2199
|
nowMs: clock(),
|
|
2073
|
-
...
|
|
2200
|
+
...optionLeewaySeconds !== undefined ? { leewaySeconds: optionLeewaySeconds } : {},
|
|
2201
|
+
...optionRequireTenant !== undefined ? { requireTenant: optionRequireTenant } : {},
|
|
2202
|
+
...expectedTid !== undefined ? { expectedTid } : {},
|
|
2074
2203
|
requiredScopes
|
|
2075
2204
|
});
|
|
2076
2205
|
if (!verified.ok) {
|
|
2077
|
-
const status = verified.reason === "insufficient_scope" ? 403 : 401;
|
|
2078
|
-
await emit({
|
|
2206
|
+
const status = verified.reason === "insufficient_scope" || verified.reason === "tenant_mismatch" || verified.reason === "tenant_required" ? 403 : 401;
|
|
2207
|
+
await emit({
|
|
2208
|
+
outcome: "deny",
|
|
2209
|
+
app,
|
|
2210
|
+
kid: ownOption2(verified, "kid") ?? null,
|
|
2211
|
+
tid: ownTenantId(verified) ?? null,
|
|
2212
|
+
...Object.hasOwn(verified, "agent") ? { agent: verified.agent } : {},
|
|
2213
|
+
reason: verified.reason,
|
|
2214
|
+
scopesRequired: requiredScopes,
|
|
2215
|
+
method,
|
|
2216
|
+
path,
|
|
2217
|
+
status,
|
|
2218
|
+
at
|
|
2219
|
+
});
|
|
2079
2220
|
return { ok: false, status, reason: verified.reason, message: verified.message };
|
|
2080
2221
|
}
|
|
2081
|
-
if (
|
|
2082
|
-
|
|
2222
|
+
if (ownKeyStatus) {
|
|
2223
|
+
let status;
|
|
2224
|
+
try {
|
|
2225
|
+
status = await ownKeyStatus(verified.kid);
|
|
2226
|
+
} catch {
|
|
2227
|
+
await emit({ outcome: "deny", app, kid: verified.kid, tid: verified.tid, agent: verified.agent, reason: "status_unavailable", scopesRequired: requiredScopes, method, path, status: 503, at });
|
|
2228
|
+
return {
|
|
2229
|
+
ok: false,
|
|
2230
|
+
status: 503,
|
|
2231
|
+
reason: "status_unavailable",
|
|
2232
|
+
message: "Could not verify API key status. Try again shortly."
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
if (status !== "active") {
|
|
2236
|
+
const known = status === "revoked" || status === "expired" || status === "unknown";
|
|
2237
|
+
if (!(status === "unknown" && allowUnregistered)) {
|
|
2238
|
+
const reason = status === "revoked" || status === "expired" ? status : "unknown_key";
|
|
2239
|
+
const message = reason === "unknown_key" ? known ? "API key is not registered with this service." : "API key status could not be recognized." : status === "expired" ? "API key has expired." : "API key has been revoked.";
|
|
2240
|
+
await emit({ outcome: "deny", app, kid: verified.kid, tid: verified.tid, agent: verified.agent, reason, scopesRequired: requiredScopes, method, path, status: 401, at });
|
|
2241
|
+
return { ok: false, status: 401, reason, message };
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
} else if (ownIsRevoked) {
|
|
2245
|
+
let revoked;
|
|
2246
|
+
try {
|
|
2247
|
+
revoked = await ownIsRevoked(verified.kid);
|
|
2248
|
+
} catch {
|
|
2249
|
+
await emit({ outcome: "deny", app, kid: verified.kid, tid: verified.tid, agent: verified.agent, reason: "status_unavailable", scopesRequired: requiredScopes, method, path, status: 503, at });
|
|
2250
|
+
return {
|
|
2251
|
+
ok: false,
|
|
2252
|
+
status: 503,
|
|
2253
|
+
reason: "status_unavailable",
|
|
2254
|
+
message: "Could not verify API key status. Try again shortly."
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2083
2257
|
if (revoked) {
|
|
2084
|
-
await emit({ outcome: "deny", app:
|
|
2258
|
+
await emit({ outcome: "deny", app, kid: verified.kid, tid: verified.tid, agent: verified.agent, reason: "revoked", scopesRequired: requiredScopes, method, path, status: 401, at });
|
|
2085
2259
|
return { ok: false, status: 401, reason: "revoked", message: "API key has been revoked." };
|
|
2086
2260
|
}
|
|
2087
2261
|
}
|
|
@@ -2089,13 +2263,14 @@ function verifyApiKey(options) {
|
|
|
2089
2263
|
kid: verified.kid,
|
|
2090
2264
|
app: verified.app,
|
|
2091
2265
|
scopes: verified.claims.scopes,
|
|
2092
|
-
agent: verified.
|
|
2266
|
+
agent: verified.agent,
|
|
2267
|
+
tid: verified.tid,
|
|
2093
2268
|
claims: verified.claims
|
|
2094
2269
|
};
|
|
2095
|
-
await emit({ outcome: "allow", app:
|
|
2270
|
+
await emit({ outcome: "allow", app, kid: verified.kid, tid: verified.tid, agent: verified.agent, reason: null, scopesRequired: requiredScopes, method, path, status: 200, at });
|
|
2096
2271
|
return { ok: true, status: 200, principal };
|
|
2097
2272
|
}
|
|
2098
|
-
return { authenticate, app
|
|
2273
|
+
return { authenticate, app };
|
|
2099
2274
|
}
|
|
2100
2275
|
function honoApiKey(options) {
|
|
2101
2276
|
const verifier = verifyApiKey(options);
|
|
@@ -2111,6 +2286,7 @@ function honoApiKey(options) {
|
|
|
2111
2286
|
return c.json({ error: decision.message, reason: decision.reason }, decision.status);
|
|
2112
2287
|
};
|
|
2113
2288
|
}
|
|
2289
|
+
var MAX_FLEET_TOKEN_TTL_SECONDS = 24 * 60 * 60;
|
|
2114
2290
|
|
|
2115
2291
|
// src/generated/storage-kit/own.ts
|
|
2116
2292
|
function ownProp(source, key) {
|
|
@@ -2936,113 +3112,113 @@ import { basename, dirname as dirname2, isAbsolute, join as join2, parse, relati
|
|
|
2936
3112
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
2937
3113
|
var exports_external = {};
|
|
2938
3114
|
__export(exports_external, {
|
|
2939
|
-
|
|
2940
|
-
util: () => util,
|
|
2941
|
-
unknown: () => unknownType,
|
|
2942
|
-
union: () => unionType,
|
|
2943
|
-
undefined: () => undefinedType,
|
|
2944
|
-
tuple: () => tupleType,
|
|
2945
|
-
transformer: () => effectsType,
|
|
2946
|
-
symbol: () => symbolType,
|
|
2947
|
-
string: () => stringType,
|
|
2948
|
-
strictObject: () => strictObjectType,
|
|
2949
|
-
setErrorMap: () => setErrorMap,
|
|
2950
|
-
set: () => setType,
|
|
2951
|
-
record: () => recordType,
|
|
2952
|
-
quotelessJson: () => quotelessJson,
|
|
2953
|
-
promise: () => promiseType,
|
|
2954
|
-
preprocess: () => preprocessType,
|
|
2955
|
-
pipeline: () => pipelineType,
|
|
2956
|
-
ostring: () => ostring,
|
|
2957
|
-
optional: () => optionalType,
|
|
2958
|
-
onumber: () => onumber,
|
|
2959
|
-
oboolean: () => oboolean,
|
|
2960
|
-
objectUtil: () => objectUtil,
|
|
2961
|
-
object: () => objectType,
|
|
2962
|
-
number: () => numberType,
|
|
2963
|
-
nullable: () => nullableType,
|
|
2964
|
-
null: () => nullType,
|
|
2965
|
-
never: () => neverType,
|
|
2966
|
-
nativeEnum: () => nativeEnumType,
|
|
2967
|
-
nan: () => nanType,
|
|
2968
|
-
map: () => mapType,
|
|
2969
|
-
makeIssue: () => makeIssue,
|
|
2970
|
-
literal: () => literalType,
|
|
2971
|
-
lazy: () => lazyType,
|
|
2972
|
-
late: () => late,
|
|
2973
|
-
isValid: () => isValid,
|
|
2974
|
-
isDirty: () => isDirty,
|
|
2975
|
-
isAsync: () => isAsync,
|
|
2976
|
-
isAborted: () => isAborted,
|
|
2977
|
-
intersection: () => intersectionType,
|
|
2978
|
-
instanceof: () => instanceOfType,
|
|
2979
|
-
getParsedType: () => getParsedType,
|
|
2980
|
-
getErrorMap: () => getErrorMap,
|
|
2981
|
-
function: () => functionType,
|
|
2982
|
-
enum: () => enumType,
|
|
2983
|
-
effect: () => effectsType,
|
|
2984
|
-
discriminatedUnion: () => discriminatedUnionType,
|
|
2985
|
-
defaultErrorMap: () => en_default,
|
|
2986
|
-
datetimeRegex: () => datetimeRegex,
|
|
2987
|
-
date: () => dateType,
|
|
2988
|
-
custom: () => custom,
|
|
2989
|
-
coerce: () => coerce,
|
|
2990
|
-
boolean: () => booleanType,
|
|
2991
|
-
bigint: () => bigIntType,
|
|
2992
|
-
array: () => arrayType,
|
|
2993
|
-
any: () => anyType,
|
|
2994
|
-
addIssueToContext: () => addIssueToContext,
|
|
2995
|
-
ZodVoid: () => ZodVoid,
|
|
2996
|
-
ZodUnknown: () => ZodUnknown,
|
|
2997
|
-
ZodUnion: () => ZodUnion,
|
|
2998
|
-
ZodUndefined: () => ZodUndefined,
|
|
2999
|
-
ZodType: () => ZodType,
|
|
3000
|
-
ZodTuple: () => ZodTuple,
|
|
3001
|
-
ZodTransformer: () => ZodEffects,
|
|
3002
|
-
ZodSymbol: () => ZodSymbol,
|
|
3003
|
-
ZodString: () => ZodString,
|
|
3004
|
-
ZodSet: () => ZodSet,
|
|
3005
|
-
ZodSchema: () => ZodType,
|
|
3006
|
-
ZodRecord: () => ZodRecord,
|
|
3007
|
-
ZodReadonly: () => ZodReadonly,
|
|
3008
|
-
ZodPromise: () => ZodPromise,
|
|
3009
|
-
ZodPipeline: () => ZodPipeline,
|
|
3010
|
-
ZodParsedType: () => ZodParsedType,
|
|
3011
|
-
ZodOptional: () => ZodOptional,
|
|
3012
|
-
ZodObject: () => ZodObject,
|
|
3013
|
-
ZodNumber: () => ZodNumber,
|
|
3014
|
-
ZodNullable: () => ZodNullable,
|
|
3015
|
-
ZodNull: () => ZodNull,
|
|
3016
|
-
ZodNever: () => ZodNever,
|
|
3017
|
-
ZodNativeEnum: () => ZodNativeEnum,
|
|
3018
|
-
ZodNaN: () => ZodNaN,
|
|
3019
|
-
ZodMap: () => ZodMap,
|
|
3020
|
-
ZodLiteral: () => ZodLiteral,
|
|
3021
|
-
ZodLazy: () => ZodLazy,
|
|
3022
|
-
ZodIssueCode: () => ZodIssueCode,
|
|
3023
|
-
ZodIntersection: () => ZodIntersection,
|
|
3024
|
-
ZodFunction: () => ZodFunction,
|
|
3025
|
-
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
3026
|
-
ZodError: () => ZodError,
|
|
3027
|
-
ZodEnum: () => ZodEnum,
|
|
3028
|
-
ZodEffects: () => ZodEffects,
|
|
3029
|
-
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
3030
|
-
ZodDefault: () => ZodDefault,
|
|
3031
|
-
ZodDate: () => ZodDate,
|
|
3032
|
-
ZodCatch: () => ZodCatch,
|
|
3033
|
-
ZodBranded: () => ZodBranded,
|
|
3034
|
-
ZodBoolean: () => ZodBoolean,
|
|
3035
|
-
ZodBigInt: () => ZodBigInt,
|
|
3036
|
-
ZodArray: () => ZodArray,
|
|
3037
|
-
ZodAny: () => ZodAny,
|
|
3038
|
-
Schema: () => ZodType,
|
|
3039
|
-
ParseStatus: () => ParseStatus,
|
|
3040
|
-
OK: () => OK,
|
|
3041
|
-
NEVER: () => NEVER,
|
|
3042
|
-
INVALID: () => INVALID,
|
|
3043
|
-
EMPTY_PATH: () => EMPTY_PATH,
|
|
3115
|
+
BRAND: () => BRAND,
|
|
3044
3116
|
DIRTY: () => DIRTY,
|
|
3045
|
-
|
|
3117
|
+
EMPTY_PATH: () => EMPTY_PATH,
|
|
3118
|
+
INVALID: () => INVALID,
|
|
3119
|
+
NEVER: () => NEVER,
|
|
3120
|
+
OK: () => OK,
|
|
3121
|
+
ParseStatus: () => ParseStatus,
|
|
3122
|
+
Schema: () => ZodType,
|
|
3123
|
+
ZodAny: () => ZodAny,
|
|
3124
|
+
ZodArray: () => ZodArray,
|
|
3125
|
+
ZodBigInt: () => ZodBigInt,
|
|
3126
|
+
ZodBoolean: () => ZodBoolean,
|
|
3127
|
+
ZodBranded: () => ZodBranded,
|
|
3128
|
+
ZodCatch: () => ZodCatch,
|
|
3129
|
+
ZodDate: () => ZodDate,
|
|
3130
|
+
ZodDefault: () => ZodDefault,
|
|
3131
|
+
ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
|
|
3132
|
+
ZodEffects: () => ZodEffects,
|
|
3133
|
+
ZodEnum: () => ZodEnum,
|
|
3134
|
+
ZodError: () => ZodError,
|
|
3135
|
+
ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
|
|
3136
|
+
ZodFunction: () => ZodFunction,
|
|
3137
|
+
ZodIntersection: () => ZodIntersection,
|
|
3138
|
+
ZodIssueCode: () => ZodIssueCode,
|
|
3139
|
+
ZodLazy: () => ZodLazy,
|
|
3140
|
+
ZodLiteral: () => ZodLiteral,
|
|
3141
|
+
ZodMap: () => ZodMap,
|
|
3142
|
+
ZodNaN: () => ZodNaN,
|
|
3143
|
+
ZodNativeEnum: () => ZodNativeEnum,
|
|
3144
|
+
ZodNever: () => ZodNever,
|
|
3145
|
+
ZodNull: () => ZodNull,
|
|
3146
|
+
ZodNullable: () => ZodNullable,
|
|
3147
|
+
ZodNumber: () => ZodNumber,
|
|
3148
|
+
ZodObject: () => ZodObject,
|
|
3149
|
+
ZodOptional: () => ZodOptional,
|
|
3150
|
+
ZodParsedType: () => ZodParsedType,
|
|
3151
|
+
ZodPipeline: () => ZodPipeline,
|
|
3152
|
+
ZodPromise: () => ZodPromise,
|
|
3153
|
+
ZodReadonly: () => ZodReadonly,
|
|
3154
|
+
ZodRecord: () => ZodRecord,
|
|
3155
|
+
ZodSchema: () => ZodType,
|
|
3156
|
+
ZodSet: () => ZodSet,
|
|
3157
|
+
ZodString: () => ZodString,
|
|
3158
|
+
ZodSymbol: () => ZodSymbol,
|
|
3159
|
+
ZodTransformer: () => ZodEffects,
|
|
3160
|
+
ZodTuple: () => ZodTuple,
|
|
3161
|
+
ZodType: () => ZodType,
|
|
3162
|
+
ZodUndefined: () => ZodUndefined,
|
|
3163
|
+
ZodUnion: () => ZodUnion,
|
|
3164
|
+
ZodUnknown: () => ZodUnknown,
|
|
3165
|
+
ZodVoid: () => ZodVoid,
|
|
3166
|
+
addIssueToContext: () => addIssueToContext,
|
|
3167
|
+
any: () => anyType,
|
|
3168
|
+
array: () => arrayType,
|
|
3169
|
+
bigint: () => bigIntType,
|
|
3170
|
+
boolean: () => booleanType,
|
|
3171
|
+
coerce: () => coerce,
|
|
3172
|
+
custom: () => custom,
|
|
3173
|
+
date: () => dateType,
|
|
3174
|
+
datetimeRegex: () => datetimeRegex,
|
|
3175
|
+
defaultErrorMap: () => en_default,
|
|
3176
|
+
discriminatedUnion: () => discriminatedUnionType,
|
|
3177
|
+
effect: () => effectsType,
|
|
3178
|
+
enum: () => enumType,
|
|
3179
|
+
function: () => functionType,
|
|
3180
|
+
getErrorMap: () => getErrorMap,
|
|
3181
|
+
getParsedType: () => getParsedType,
|
|
3182
|
+
instanceof: () => instanceOfType,
|
|
3183
|
+
intersection: () => intersectionType,
|
|
3184
|
+
isAborted: () => isAborted,
|
|
3185
|
+
isAsync: () => isAsync,
|
|
3186
|
+
isDirty: () => isDirty,
|
|
3187
|
+
isValid: () => isValid,
|
|
3188
|
+
late: () => late,
|
|
3189
|
+
lazy: () => lazyType,
|
|
3190
|
+
literal: () => literalType,
|
|
3191
|
+
makeIssue: () => makeIssue,
|
|
3192
|
+
map: () => mapType,
|
|
3193
|
+
nan: () => nanType,
|
|
3194
|
+
nativeEnum: () => nativeEnumType,
|
|
3195
|
+
never: () => neverType,
|
|
3196
|
+
null: () => nullType,
|
|
3197
|
+
nullable: () => nullableType,
|
|
3198
|
+
number: () => numberType,
|
|
3199
|
+
object: () => objectType,
|
|
3200
|
+
objectUtil: () => objectUtil,
|
|
3201
|
+
oboolean: () => oboolean,
|
|
3202
|
+
onumber: () => onumber,
|
|
3203
|
+
optional: () => optionalType,
|
|
3204
|
+
ostring: () => ostring,
|
|
3205
|
+
pipeline: () => pipelineType,
|
|
3206
|
+
preprocess: () => preprocessType,
|
|
3207
|
+
promise: () => promiseType,
|
|
3208
|
+
quotelessJson: () => quotelessJson,
|
|
3209
|
+
record: () => recordType,
|
|
3210
|
+
set: () => setType,
|
|
3211
|
+
setErrorMap: () => setErrorMap,
|
|
3212
|
+
strictObject: () => strictObjectType,
|
|
3213
|
+
string: () => stringType,
|
|
3214
|
+
symbol: () => symbolType,
|
|
3215
|
+
transformer: () => effectsType,
|
|
3216
|
+
tuple: () => tupleType,
|
|
3217
|
+
undefined: () => undefinedType,
|
|
3218
|
+
union: () => unionType,
|
|
3219
|
+
unknown: () => unknownType,
|
|
3220
|
+
util: () => util,
|
|
3221
|
+
void: () => voidType
|
|
3046
3222
|
});
|
|
3047
3223
|
|
|
3048
3224
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
@@ -7145,6 +7321,9 @@ var DEPRECATED_CONFIG_AGENT_SET = new Set(DEPRECATED_CONFIG_AGENTS);
|
|
|
7145
7321
|
|
|
7146
7322
|
// src/lib/cursor-authority.ts
|
|
7147
7323
|
var CURSOR_GLOBAL_AUTHORITY_MAX_BYTES = 256 * 1024;
|
|
7324
|
+
|
|
7325
|
+
// src/lib/session-authority.ts
|
|
7326
|
+
var CLAUDE_LEGACY_AUTHORITY_MAX_BYTES = 256 * 1024;
|
|
7148
7327
|
// src/lib/session-render.ts
|
|
7149
7328
|
var SESSION_RENDER_PROFILE_ENTRYPOINTS = [
|
|
7150
7329
|
".claude/CLAUDE.md",
|
|
@@ -7602,9 +7781,15 @@ async function createConfig2(client, input) {
|
|
|
7602
7781
|
throw new Error("category is required");
|
|
7603
7782
|
const id = randomUUID();
|
|
7604
7783
|
const slug = await uniqueSlug(client, input.name);
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7784
|
+
const snapshotId = randomUUID();
|
|
7785
|
+
await client.execute(`WITH inserted_config AS (
|
|
7786
|
+
INSERT INTO configs
|
|
7787
|
+
(id, name, slug, kind, category, agent, target_path, outputs, format, content, description, tags, is_template, version, created_at, updated_at)
|
|
7788
|
+
VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb,$9,$10,$11,$12::jsonb,$13,1,now(),now())
|
|
7789
|
+
RETURNING id, content, version
|
|
7790
|
+
)
|
|
7791
|
+
INSERT INTO config_snapshots (id, config_id, content, version, created_at)
|
|
7792
|
+
SELECT $14, id, content, version, now() FROM inserted_config`, [
|
|
7608
7793
|
id,
|
|
7609
7794
|
input.name,
|
|
7610
7795
|
slug,
|
|
@@ -7617,7 +7802,8 @@ async function createConfig2(client, input) {
|
|
|
7617
7802
|
input.content ?? "",
|
|
7618
7803
|
input.description ?? null,
|
|
7619
7804
|
JSON.stringify(input.tags ?? []),
|
|
7620
|
-
input.is_template ?? false
|
|
7805
|
+
input.is_template ?? false,
|
|
7806
|
+
snapshotId
|
|
7621
7807
|
]);
|
|
7622
7808
|
return getConfig2(client, id);
|
|
7623
7809
|
}
|
|
@@ -7656,7 +7842,15 @@ async function updateConfig2(client, idOrSlug, input) {
|
|
|
7656
7842
|
if (input.synced_at !== undefined)
|
|
7657
7843
|
set("synced_at", input.synced_at, "::timestamptz");
|
|
7658
7844
|
params.push(existing.id);
|
|
7659
|
-
|
|
7845
|
+
const configIdParam = params.length;
|
|
7846
|
+
params.push(randomUUID());
|
|
7847
|
+
const snapshotIdParam = params.length;
|
|
7848
|
+
await client.execute(`WITH updated_config AS (
|
|
7849
|
+
UPDATE configs SET ${sets.join(", ")} WHERE id = $${configIdParam}
|
|
7850
|
+
RETURNING id, content, version
|
|
7851
|
+
)
|
|
7852
|
+
INSERT INTO config_snapshots (id, config_id, content, version, created_at)
|
|
7853
|
+
SELECT $${snapshotIdParam}, id, content, version, now() FROM updated_config`, params);
|
|
7660
7854
|
return getConfig2(client, existing.id);
|
|
7661
7855
|
}
|
|
7662
7856
|
async function deleteConfig2(client, idOrSlug) {
|