@hasna/skills 0.10.11 → 0.10.14
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/bin/index.js +203 -9
- package/bin/maintenance.js +226 -1044
- package/bin/mcp.js +1 -1
- package/bin/migrate.js +1 -1
- package/bin/server.js +9 -7
- package/bin/worker.js +9 -7
- package/dist/index.js +200 -5
- package/dist/lib/agent-codex.d.ts +7 -3
- package/dist/lib/agent-integration.d.ts +1 -0
- package/dist/lib/codex-hook-rpc.d.ts +1 -1
- package/dist/sdk/index.js +208 -11
- package/dist/server/enrollment-inspection.d.ts +26 -0
- package/dist/server/maintenance-entry.d.ts +13 -0
- package/dist/server/store.d.ts +9 -1
- package/package.json +1 -1
package/dist/sdk/index.js
CHANGED
|
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
|
|
|
32373
32373
|
// package.json
|
|
32374
32374
|
var package_default = {
|
|
32375
32375
|
name: "@hasna/skills",
|
|
32376
|
-
version: "0.10.
|
|
32376
|
+
version: "0.10.14",
|
|
32377
32377
|
description: "Skills library for AI coding agents",
|
|
32378
32378
|
type: "module",
|
|
32379
32379
|
bin: {
|
|
@@ -40984,6 +40984,196 @@ export default async ({ directory }) => {
|
|
|
40984
40984
|
// src/lib/agent-codex.ts
|
|
40985
40985
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
|
|
40986
40986
|
var CODEX_SKILL_CONFIG_SECTIONS = /^\[\[skills\.config\]\][^\n]*(?:\n(?!\s*\[)[^\n]*)*/gm;
|
|
40987
|
+
var codexPathConfigRefusal = () => new Error("Codex skill path controls require ordinary [[skills.config]] TOML tables or a native single-line inline array; preserve and review unsupported inline, dotted, or malformed definitions before running skills hook install");
|
|
40988
|
+
function splitTopLevel(value, delimiter) {
|
|
40989
|
+
const result = [];
|
|
40990
|
+
let start = 0, square = 0, curly = 0, quote2 = null, escaped = false;
|
|
40991
|
+
for (let index = 0;index < value.length; index++) {
|
|
40992
|
+
const char = value[index];
|
|
40993
|
+
if (quote2 === "double") {
|
|
40994
|
+
if (escaped)
|
|
40995
|
+
escaped = false;
|
|
40996
|
+
else if (char === "\\")
|
|
40997
|
+
escaped = true;
|
|
40998
|
+
else if (char === '"')
|
|
40999
|
+
quote2 = null;
|
|
41000
|
+
continue;
|
|
41001
|
+
}
|
|
41002
|
+
if (quote2 === "literal") {
|
|
41003
|
+
if (char === "'")
|
|
41004
|
+
quote2 = null;
|
|
41005
|
+
continue;
|
|
41006
|
+
}
|
|
41007
|
+
if (char === '"') {
|
|
41008
|
+
quote2 = "double";
|
|
41009
|
+
continue;
|
|
41010
|
+
}
|
|
41011
|
+
if (char === "'") {
|
|
41012
|
+
quote2 = "literal";
|
|
41013
|
+
continue;
|
|
41014
|
+
}
|
|
41015
|
+
if (char === "[")
|
|
41016
|
+
square++;
|
|
41017
|
+
else if (char === "]") {
|
|
41018
|
+
if (--square < 0)
|
|
41019
|
+
return null;
|
|
41020
|
+
} else if (char === "{")
|
|
41021
|
+
curly++;
|
|
41022
|
+
else if (char === "}") {
|
|
41023
|
+
if (--curly < 0)
|
|
41024
|
+
return null;
|
|
41025
|
+
} else if (char === delimiter && square === 0 && curly === 0) {
|
|
41026
|
+
result.push(value.slice(start, index));
|
|
41027
|
+
start = index + 1;
|
|
41028
|
+
}
|
|
41029
|
+
}
|
|
41030
|
+
if (quote2 !== null || square !== 0 || curly !== 0)
|
|
41031
|
+
return null;
|
|
41032
|
+
result.push(value.slice(start));
|
|
41033
|
+
return result;
|
|
41034
|
+
}
|
|
41035
|
+
function inlineArrayEnd(value) {
|
|
41036
|
+
if (!value.startsWith("["))
|
|
41037
|
+
return null;
|
|
41038
|
+
let square = 0, curly = 0, quote2 = null, escaped = false;
|
|
41039
|
+
for (let index = 0;index < value.length; index++) {
|
|
41040
|
+
const char = value[index];
|
|
41041
|
+
if (quote2 === "double") {
|
|
41042
|
+
if (escaped)
|
|
41043
|
+
escaped = false;
|
|
41044
|
+
else if (char === "\\")
|
|
41045
|
+
escaped = true;
|
|
41046
|
+
else if (char === '"')
|
|
41047
|
+
quote2 = null;
|
|
41048
|
+
continue;
|
|
41049
|
+
}
|
|
41050
|
+
if (quote2 === "literal") {
|
|
41051
|
+
if (char === "'")
|
|
41052
|
+
quote2 = null;
|
|
41053
|
+
continue;
|
|
41054
|
+
}
|
|
41055
|
+
if (char === '"') {
|
|
41056
|
+
quote2 = "double";
|
|
41057
|
+
continue;
|
|
41058
|
+
}
|
|
41059
|
+
if (char === "'") {
|
|
41060
|
+
quote2 = "literal";
|
|
41061
|
+
continue;
|
|
41062
|
+
}
|
|
41063
|
+
if (char === "[")
|
|
41064
|
+
square++;
|
|
41065
|
+
else if (char === "]") {
|
|
41066
|
+
if (--square < 0)
|
|
41067
|
+
return null;
|
|
41068
|
+
if (square === 0 && curly === 0)
|
|
41069
|
+
return index;
|
|
41070
|
+
} else if (char === "{")
|
|
41071
|
+
curly++;
|
|
41072
|
+
else if (char === "}") {
|
|
41073
|
+
if (--curly < 0)
|
|
41074
|
+
return null;
|
|
41075
|
+
}
|
|
41076
|
+
}
|
|
41077
|
+
return null;
|
|
41078
|
+
}
|
|
41079
|
+
function inlineRowsAsTables(value, newline) {
|
|
41080
|
+
const end = inlineArrayEnd(value);
|
|
41081
|
+
if (end === null || value.slice(end + 1).trim() !== "" || value.includes(`
|
|
41082
|
+
`) || value.includes("\r"))
|
|
41083
|
+
return null;
|
|
41084
|
+
const elements = splitTopLevel(value.slice(1, end), ",");
|
|
41085
|
+
if (!elements)
|
|
41086
|
+
return null;
|
|
41087
|
+
const rows = elements.map((element) => element.trim()).filter(Boolean);
|
|
41088
|
+
if (rows.length === 0)
|
|
41089
|
+
return "";
|
|
41090
|
+
const sections = [];
|
|
41091
|
+
for (const row of rows) {
|
|
41092
|
+
if (!row.startsWith("{") || !row.endsWith("}"))
|
|
41093
|
+
return null;
|
|
41094
|
+
const fields = splitTopLevel(row.slice(1, -1), ",");
|
|
41095
|
+
if (!fields)
|
|
41096
|
+
return null;
|
|
41097
|
+
const lines = fields.map((field2) => field2.trim()).filter(Boolean);
|
|
41098
|
+
if (lines.some((line) => !/^(?:path|name|enabled)\s*=/.test(line)))
|
|
41099
|
+
return null;
|
|
41100
|
+
const keys2 = lines.map((line) => line.slice(0, line.indexOf("=")).trim());
|
|
41101
|
+
if (new Set(keys2).size !== keys2.length)
|
|
41102
|
+
return null;
|
|
41103
|
+
sections.push(`[[skills.config]]${newline}${lines.join(newline)}${newline}`);
|
|
41104
|
+
}
|
|
41105
|
+
return sections.join("");
|
|
41106
|
+
}
|
|
41107
|
+
function normalizeCodexInlinePathConfig(text2) {
|
|
41108
|
+
const before = Bun.TOML.parse(text2);
|
|
41109
|
+
if (!Array.isArray(before.skills?.config))
|
|
41110
|
+
return text2;
|
|
41111
|
+
if (before.skills.config.length === 0)
|
|
41112
|
+
throw codexPathConfigRefusal();
|
|
41113
|
+
const expectedWithoutConfig = structuredClone(before);
|
|
41114
|
+
delete expectedWithoutConfig.skills.config;
|
|
41115
|
+
try {
|
|
41116
|
+
if (isDeepStrictEqual4(Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, "")), expectedWithoutConfig))
|
|
41117
|
+
return text2;
|
|
41118
|
+
} catch {}
|
|
41119
|
+
const matches = [];
|
|
41120
|
+
for (const assignment of text2.matchAll(/^([ \t]*config[ \t]*=[ \t]*)(.*?)(\r?)$/gm)) {
|
|
41121
|
+
const rawValue = assignment[2].trimEnd();
|
|
41122
|
+
let quote2 = null, escaped = false, comment = "";
|
|
41123
|
+
for (let index = 0;index < rawValue.length; index++) {
|
|
41124
|
+
const char = rawValue[index];
|
|
41125
|
+
if (quote2 === "double") {
|
|
41126
|
+
if (escaped)
|
|
41127
|
+
escaped = false;
|
|
41128
|
+
else if (char === "\\")
|
|
41129
|
+
escaped = true;
|
|
41130
|
+
else if (char === '"')
|
|
41131
|
+
quote2 = null;
|
|
41132
|
+
continue;
|
|
41133
|
+
}
|
|
41134
|
+
if (quote2 === "literal") {
|
|
41135
|
+
if (char === "'")
|
|
41136
|
+
quote2 = null;
|
|
41137
|
+
continue;
|
|
41138
|
+
}
|
|
41139
|
+
if (char === '"')
|
|
41140
|
+
quote2 = "double";
|
|
41141
|
+
else if (char === "'")
|
|
41142
|
+
quote2 = "literal";
|
|
41143
|
+
else if (char === "#") {
|
|
41144
|
+
comment = rawValue.slice(index);
|
|
41145
|
+
break;
|
|
41146
|
+
}
|
|
41147
|
+
}
|
|
41148
|
+
const value = comment ? rawValue.slice(0, rawValue.length - comment.length).trimEnd() : rawValue;
|
|
41149
|
+
const tableSections = inlineRowsAsTables(value, text2.includes(`\r
|
|
41150
|
+
`) ? `\r
|
|
41151
|
+
` : `
|
|
41152
|
+
`);
|
|
41153
|
+
if (tableSections === null)
|
|
41154
|
+
continue;
|
|
41155
|
+
const start = assignment.index;
|
|
41156
|
+
const end = start + assignment[0].length;
|
|
41157
|
+
const withoutAssignment = text2.slice(0, start) + (comment ? comment : "") + assignment[3] + text2.slice(end);
|
|
41158
|
+
const separator = withoutAssignment.endsWith(`
|
|
41159
|
+
`) ? withoutAssignment.endsWith(`
|
|
41160
|
+
|
|
41161
|
+
`) ? "" : `
|
|
41162
|
+
` : `
|
|
41163
|
+
|
|
41164
|
+
`;
|
|
41165
|
+
const candidate2 = withoutAssignment + (tableSections ? separator + tableSections : "");
|
|
41166
|
+
try {
|
|
41167
|
+
const after = Bun.TOML.parse(candidate2);
|
|
41168
|
+
const expected = structuredClone(before);
|
|
41169
|
+
if (isDeepStrictEqual4(after, expected))
|
|
41170
|
+
matches.push(candidate2);
|
|
41171
|
+
} catch {}
|
|
41172
|
+
}
|
|
41173
|
+
if (matches.length !== 1)
|
|
41174
|
+
throw codexPathConfigRefusal();
|
|
41175
|
+
return matches[0];
|
|
41176
|
+
}
|
|
40987
41177
|
function assertCodexPathConfigEditable(text2) {
|
|
40988
41178
|
const before = Bun.TOML.parse(text2);
|
|
40989
41179
|
if (before.skills?.config === undefined)
|
|
@@ -40994,8 +41184,12 @@ function assertCodexPathConfigEditable(text2) {
|
|
|
40994
41184
|
const withoutSections = Bun.TOML.parse(text2.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
40995
41185
|
if (isDeepStrictEqual4(withoutSections, expected))
|
|
40996
41186
|
return;
|
|
41187
|
+
const normalized = normalizeCodexInlinePathConfig(text2);
|
|
41188
|
+
const withoutNormalizedSections = Bun.TOML.parse(normalized.replace(CODEX_SKILL_CONFIG_SECTIONS, ""));
|
|
41189
|
+
if (isDeepStrictEqual4(withoutNormalizedSections, expected))
|
|
41190
|
+
return;
|
|
40997
41191
|
} catch {}
|
|
40998
|
-
throw
|
|
41192
|
+
throw codexPathConfigRefusal();
|
|
40999
41193
|
}
|
|
41000
41194
|
function disableCodexBundledSkills(text2) {
|
|
41001
41195
|
const before = Bun.TOML.parse(text2);
|
|
@@ -41271,11 +41465,12 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
|
|
|
41271
41465
|
return false;
|
|
41272
41466
|
if (scan.hasSkills) {
|
|
41273
41467
|
const targetSkills = entries.filter((entry) => entry.agent === agent && entry.vendor && (entry.path === target || entry.path.startsWith(target + sep4)));
|
|
41468
|
+
if (path === options.reviewedCacheAlias && targetSkills.length > 0)
|
|
41469
|
+
reviewedCacheAliasFound = true;
|
|
41274
41470
|
if (agent === "codex" && targetSkills.length > 0 && targetSkills.every((entry) => disabledVendorPaths.has(entry.path)))
|
|
41275
41471
|
return true;
|
|
41276
41472
|
if (path !== options.reviewedCacheAlias)
|
|
41277
41473
|
return false;
|
|
41278
|
-
reviewedCacheAliasFound = true;
|
|
41279
41474
|
}
|
|
41280
41475
|
return true;
|
|
41281
41476
|
}
|
|
@@ -41474,7 +41669,7 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
|
|
|
41474
41669
|
}
|
|
41475
41670
|
function disableCodexSkills(text2, skills, aliases, bridgePath) {
|
|
41476
41671
|
const bundled = disableCodexBundledSkills(text2);
|
|
41477
|
-
let result = bundled;
|
|
41672
|
+
let result = normalizeCodexInlinePathConfig(bundled);
|
|
41478
41673
|
const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve14(bridgePath), resolve14(join21(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
|
|
41479
41674
|
const previousConfig = Bun.TOML.parse(bundled).skills?.config;
|
|
41480
41675
|
if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
|
|
@@ -41543,7 +41738,7 @@ function planAgentIntegration(options) {
|
|
|
41543
41738
|
return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
|
|
41544
41739
|
});
|
|
41545
41740
|
const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join21(home, ".codex", "config.toml"), aliases)) ?? "") : {};
|
|
41546
|
-
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
|
|
41741
|
+
const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
|
|
41547
41742
|
const changes = [];
|
|
41548
41743
|
for (const agent of [...new Set(options.agents)]) {
|
|
41549
41744
|
if (!INTEGRATION_AGENTS.includes(agent))
|
|
@@ -64005,9 +64200,9 @@ class PostgresSkillsStore {
|
|
|
64005
64200
|
}
|
|
64006
64201
|
backend = { kind: "postgres", durable: true, label: "postgres" };
|
|
64007
64202
|
sql;
|
|
64008
|
-
constructor(databaseUrl) {
|
|
64203
|
+
constructor(databaseUrl, connectionOptions = {}) {
|
|
64009
64204
|
const bunWithSql = Bun;
|
|
64010
|
-
this.sql = new bunWithSql.SQL(databaseUrl, { max: resolvePoolMax() });
|
|
64205
|
+
this.sql = new bunWithSql.SQL(databaseUrl, { max: resolvePoolMax(), ...connectionOptions });
|
|
64011
64206
|
}
|
|
64012
64207
|
async verifyConnectivity() {
|
|
64013
64208
|
try {
|
|
@@ -64102,7 +64297,7 @@ class PostgresSkillsStore {
|
|
|
64102
64297
|
}
|
|
64103
64298
|
await tx`
|
|
64104
64299
|
INSERT INTO skills_audit_events (org_id, user_id, api_key_id, action, target_type, target_id, metadata_json)
|
|
64105
|
-
VALUES (${actor.orgId}, ${actor.userId}, ${actor.apiKeyId}, ${"api_key_scopes_added"}, ${"api_key"}, ${keyId}, ${JSON.stringify({ added: addScopes, scopes: parseJsonArray(updated[0].scopes_json) })}::jsonb)
|
|
64300
|
+
VALUES (${actor.orgId}, ${actor.userId}, ${actor.apiKeyId}, ${"api_key_scopes_added"}, ${"api_key"}, ${keyId}, ${JSON.stringify({ added: addScopes, scopes: parseJsonArray(updated[0].scopes_json) })}::text::jsonb)
|
|
64106
64301
|
`;
|
|
64107
64302
|
return { kind: "updated", scopes: parseJsonArray(updated[0].scopes_json) };
|
|
64108
64303
|
});
|
|
@@ -64110,10 +64305,12 @@ class PostgresSkillsStore {
|
|
|
64110
64305
|
async casUpdateApiKeyScopes(tx, keyId, orgId, expectedScopes, addScopes) {
|
|
64111
64306
|
const current = expectedScopes;
|
|
64112
64307
|
const scopes = [...current, ...addScopes.filter((scope2) => !current.includes(scope2))];
|
|
64308
|
+
const expectedScopesJson = JSON.stringify(expectedScopes);
|
|
64113
64309
|
return tx`
|
|
64114
|
-
UPDATE api_keys SET scopes_json = ${JSON.stringify(scopes)}::jsonb
|
|
64310
|
+
UPDATE api_keys SET scopes_json = ${JSON.stringify(scopes)}::text::jsonb
|
|
64115
64311
|
WHERE id = ${keyId} AND org_id = ${orgId} AND revoked_at IS NULL
|
|
64116
|
-
AND scopes_json = ${
|
|
64312
|
+
AND (scopes_json = ${expectedScopesJson}::text::jsonb
|
|
64313
|
+
OR scopes_json = to_jsonb(${expectedScopesJson}::text))
|
|
64117
64314
|
RETURNING scopes_json
|
|
64118
64315
|
`;
|
|
64119
64316
|
}
|
|
@@ -64173,7 +64370,7 @@ class PostgresSkillsStore {
|
|
|
64173
64370
|
operator_task_arn: input.operatorTaskArn,
|
|
64174
64371
|
target_manifest_digest: input.manifestDigest,
|
|
64175
64372
|
station_id: input.stationId
|
|
64176
|
-
})}::jsonb)
|
|
64373
|
+
})}::text::jsonb)
|
|
64177
64374
|
`;
|
|
64178
64375
|
return { kind: "updated", scopes };
|
|
64179
64376
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface EnrollmentInspectionInput {
|
|
2
|
+
keyId: string;
|
|
3
|
+
orgId: string;
|
|
4
|
+
enrollmentOperationId: string;
|
|
5
|
+
enrollmentManifestDigest: string;
|
|
6
|
+
}
|
|
7
|
+
export interface EnrollmentInspectionResult {
|
|
8
|
+
status: "inspected";
|
|
9
|
+
target: {
|
|
10
|
+
state: "found";
|
|
11
|
+
scopes: string[];
|
|
12
|
+
} | {
|
|
13
|
+
state: "absent" | "revoked" | "mismatched" | "ambiguous";
|
|
14
|
+
};
|
|
15
|
+
audit: {
|
|
16
|
+
state: "absent" | "matching" | "mismatched" | "ambiguous";
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
type InspectionCode = "INVALID_INSPECTION_INPUT" | "POSTGRES_REQUIRED" | "INVALID_INSPECTION_RESULT" | "INSPECTION_FAILED" | "INSPECTION_SCHEMA_UNAVAILABLE" | "INSPECTION_ACCESS_DENIED" | "INSPECTION_WRITE_REFUSED" | "INSPECTION_TIMEOUT" | "INSPECTION_CONNECTION_FAILED";
|
|
20
|
+
export declare class EnrollmentInspectionError extends Error {
|
|
21
|
+
readonly code: InspectionCode;
|
|
22
|
+
constructor(code: InspectionCode);
|
|
23
|
+
}
|
|
24
|
+
/** Inspect metadata only. Deliberately does not import or initialize the application store. */
|
|
25
|
+
export declare function inspectEnrollment(databaseUrl: string, input: EnrollmentInspectionInput): Promise<EnrollmentInspectionResult>;
|
|
26
|
+
export {};
|
|
@@ -1,2 +1,15 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
+
import { type EnrollmentInspectionInput } from "./enrollment-inspection.js";
|
|
3
|
+
type InspectionManifest = EnrollmentInspectionInput & {
|
|
4
|
+
app: "skills";
|
|
5
|
+
operation: "inspect-enrollment";
|
|
6
|
+
manifestVersion: 1;
|
|
7
|
+
operationId: string;
|
|
8
|
+
stationId: string;
|
|
9
|
+
expiresAt: string;
|
|
10
|
+
manifestDigest: string;
|
|
11
|
+
};
|
|
12
|
+
/** Inspection has its own authorization; a failed enrollment manifest cannot authorize it. */
|
|
13
|
+
export declare function readInspectionManifest(path: string, receiptPath: string): InspectionManifest;
|
|
2
14
|
export declare function registerMaintenance(parent: Command): void;
|
|
15
|
+
export {};
|
package/dist/server/store.d.ts
CHANGED
|
@@ -25,6 +25,9 @@ export interface StoreOptions {
|
|
|
25
25
|
* - anything else -> throws, naming what is supported
|
|
26
26
|
*/
|
|
27
27
|
export declare function createStore(options?: StoreOptions): Promise<SkillsProductStore>;
|
|
28
|
+
export type OperatorScopeMaintenanceStore = Required<Pick<SkillsProductStore, "inspectOperatorScopeTarget" | "enrollPublishScopeByOperator" | "close">>;
|
|
29
|
+
/** Open only the existing scope-maintenance surface; never initialize or backfill the application store. */
|
|
30
|
+
export declare function openOperatorScopeMaintenance(databaseUrl: string): OperatorScopeMaintenanceStore;
|
|
28
31
|
export declare class MemorySkillsStore implements SkillsProductStore {
|
|
29
32
|
readonly selectionStore: MemorySkillSelectionStore;
|
|
30
33
|
readonly executionGrantStore: MemoryExecutionGrantStore;
|
|
@@ -102,7 +105,12 @@ export declare class PostgresSkillsStore implements SkillsProductStore {
|
|
|
102
105
|
get executionGrantStore(): PostgresExecutionGrantStore;
|
|
103
106
|
readonly backend: StoreBackendInfo;
|
|
104
107
|
private sql;
|
|
105
|
-
constructor(databaseUrl: string
|
|
108
|
+
constructor(databaseUrl: string, connectionOptions?: {
|
|
109
|
+
max?: number;
|
|
110
|
+
connectionTimeout?: number;
|
|
111
|
+
idleTimeout?: number;
|
|
112
|
+
connection?: Record<string, string>;
|
|
113
|
+
});
|
|
106
114
|
/**
|
|
107
115
|
* Bun's SQL client connects lazily, so constructing this store proves nothing about
|
|
108
116
|
* the database being there. Without an explicit probe, a wrong host or a down
|