@govplane/runtime-sdk 0.2.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +400 -216
- package/dist/index.cjs +187 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -14
- package/dist/index.d.ts +65 -14
- package/dist/index.js +187 -91
- package/dist/index.js.map +1 -1
- package/docs/README.md +89 -0
- package/docs/SUMMARY.md +34 -0
- package/docs/installation/GettingStarted.md +474 -0
- package/docs/reference/Configuration.md +198 -0
- package/docs/reference/TypesAndInterfaces.md +373 -0
- package/docs/usage/BundleLifecycle.md +209 -0
- package/docs/usage/ConditionalRules.md +251 -0
- package/docs/usage/ContextPolicy.md +196 -0
- package/docs/usage/CustomEffect.md +217 -0
- package/docs/usage/DecisionTrace.md +289 -0
- package/docs/usage/Effects.md +213 -0
- package/docs/usage/Evaluate.md +164 -0
- package/docs/usage/PolicyDefaults.md +220 -0
- package/package.json +3 -5
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client/RuntimeClient.ts","../src/engine/context.ts","../src/engine/when.ts","../src/engine/traceDispatcher.ts","../src/engine/toStructuredTrace.ts","../src/engine/emitTrace.ts","../src/engine/createPolicyEngine.ts","../src/errors/Errors.ts","../src/engine/formatTrace.ts"],"sourcesContent":["export { RuntimeClient } from \"./client/RuntimeClient\";\nexport type { RuntimeClientConfig, RefreshResult, RuntimeCache, BundleMeta, RuntimeStatus } from \"./client/RuntimeClient\";\nexport * from \"./engine/types\";\nexport * from \"./errors/Errors.js\";\nexport * from \"./engine/context.js\";\nexport { createPolicyEngine } from \"./engine/createPolicyEngine.js\";\nexport { formatTrace } from \"./engine/formatTrace.js\";\n","import { request } from \"undici\";\nimport { createPolicyEngine } from \"../engine/createPolicyEngine\";\nimport { promises as fsp } from \"node:fs\";\nimport type {\n RuntimeBundleV1,\n Decision,\n DecisionWithOptionalTrace,\n Target,\n TraceOptions,\n StructuredTraceEvent\n} from \"../engine/types\";\nimport type { ContextPolicy } from \"../engine/context\";\nimport type { PolicyEngine } from \"../engine/types\";\n\nexport type RuntimeClientConfig = {\n baseUrl: string;\n runtimeKey: string;\n orgId: string;\n projectId: string;\n env: string;\n\n // polling\n pollMs?: number; // default 5000\n burstPollMs?: number; // default 500\n burstDurationMs?: number; // default 30000\n\n timeoutMs?: number; // default 5000\n userAgent?: string;\n\n // backoff (Phase 0+)\n backoffBaseMs?: number; // default 500\n backoffMaxMs?: number; // default 30000\n backoffJitter?: number; // default 0.2 (±20%)\n degradeAfterFailures?: number; // default 3\n\n /**\n * Engine config\n */\n engine?: {\n validateContext?: boolean; // default true\n contextPolicy?: ContextPolicy;\n };\n\n /**\n * Decision trace (SDK-only, zero PII)\n */\n trace?: {\n defaults?: TraceOptions; // level/sampling/budget/force\n onDecisionTrace?: (evt: StructuredTraceEvent) => void; // sync\n onDecisionTraceAsync?: (evt: StructuredTraceEvent) => Promise<void>; // async\n queueMax?: number; // default 1000\n dropPolicy?: \"drop_new\" | \"drop_old\"; // default drop_new\n onTraceError?: (err: unknown) => void;\n };\n\n // Incident controls (no endpoints)\n incidentEnvFlag?: string; // default \"GP_RUNTIME_INCIDENT\"\n incidentFilePath?: string; // e.g. \"/etc/govplane/incident.json\"\n incidentFilePollMs?: number; // default 1000\n incidentSignal?: \"SIGUSR1\" | false; // default \"SIGUSR1\"\n};\n\nexport type BundleMeta = {\n etag: string;\n bundleVersion?: number;\n updatedAt?: string;\n};\n\nexport type RuntimeCache<TBundle = unknown> = {\n meta?: BundleMeta;\n bundle?: TBundle;\n};\n\nexport type RefreshResult<TBundle = unknown> =\n | { changed: false; meta?: BundleMeta }\n | { changed: true; meta: BundleMeta; bundle: TBundle };\n\nexport type RuntimeStatus =\n | { state: \"warming_up\" }\n | { state: \"ok\" }\n | {\n state: \"degraded\";\n consecutiveFailures: number;\n lastError: { message: string; at: string };\n nextRetryAt?: string;\n };\n\ntype RequiredCfg =\n Required<\n Pick<\n RuntimeClientConfig,\n | \"pollMs\"\n | \"burstPollMs\"\n | \"burstDurationMs\"\n | \"timeoutMs\"\n | \"backoffBaseMs\"\n | \"backoffMaxMs\"\n | \"backoffJitter\"\n | \"degradeAfterFailures\"\n >\n > &\n Omit<\n RuntimeClientConfig,\n | \"pollMs\"\n | \"burstPollMs\"\n | \"burstDurationMs\"\n | \"timeoutMs\"\n | \"backoffBaseMs\"\n | \"backoffMaxMs\"\n | \"backoffJitter\"\n | \"degradeAfterFailures\"\n >;\n\n type IncidentFilePayload = {\n burst?: boolean;\n burstDurationMs?: number;\n burstPollMs?: number;\n refreshNow?: boolean;\n };\n\n/**\n * RuntimeClient = polling/backoff/degraded + cached runtime bundle + policy evaluation.\n *\n * - No endpoints expuestos por el cliente\n * - No PII en trace: el engine emite StructuredTraceEvent sin context ni reglas completas\n */\nexport class RuntimeClient<TBundle = RuntimeBundleV1> {\n private readonly cfg: RequiredCfg;\n\n private cache: RuntimeCache<TBundle> = {};\n private timer: NodeJS.Timeout | null = null;\n private isRunning = false;\n private hasValidBundle = false;\n\n private inFlightRefresh: Promise<RefreshResult<TBundle>> | null = null;\n private burstUntil = 0;\n\n // health / degraded state\n private consecutiveFailures = 0;\n private lastError: { message: string; at: string } | null = null;\n private nextRetryAtMs: number | null = null;\n\n private updateListeners: Array<(res: RefreshResult<TBundle>) => void> = [];\n private statusListeners: Array<(s: RuntimeStatus) => void> = [];\n\n // Policy engine\n private readonly engine: PolicyEngine;\n\n // Incident controls\n private incidentPollTimer: NodeJS.Timeout | null = null;\n private incidentFileLastMtimeMs: number | null = null;\n private installedSignalHandler = false;\n private sigHandler?: () => void;\n\n constructor(config: RuntimeClientConfig) {\n this.cfg = {\n ...config,\n pollMs: config.pollMs ?? 5000,\n burstPollMs: config.burstPollMs ?? 500,\n burstDurationMs: config.burstDurationMs ?? 30_000,\n timeoutMs: config.timeoutMs ?? 5000,\n\n backoffBaseMs: config.backoffBaseMs ?? 500,\n backoffMaxMs: config.backoffMaxMs ?? 30_000,\n backoffJitter: config.backoffJitter ?? 0.2,\n degradeAfterFailures: config.degradeAfterFailures ?? 3,\n\n incidentEnvFlag: config.incidentEnvFlag ?? \"GP_RUNTIME_INCIDENT\",\n incidentFilePollMs: config.incidentFilePollMs ?? 1000,\n incidentSignal: config.incidentSignal ?? \"SIGUSR1\"\n \n };\n\n // Wiring: el client conecta bundle cacheado + trace sinks + context policy en el engine\n this.engine = createPolicyEngine({\n getBundle: () => this.cache.bundle as any,\n\n validateContext: config.engine?.validateContext !== false,\n contextPolicy: config.engine?.contextPolicy,\n\n traceDefaults: config.trace?.defaults,\n traceSink: config.trace?.onDecisionTrace,\n traceSinkAsync: config.trace?.onDecisionTraceAsync,\n traceQueueMax: config.trace?.queueMax,\n traceQueueDropPolicy: config.trace?.dropPolicy,\n onTraceSinkError: config.trace?.onTraceError\n });\n }\n\n /** Subscribe to bundle updates (only when changed). */\n onUpdate(fn: (res: Extract<RefreshResult<TBundle>, { changed: true }>) => void) {\n const wrapped = (res: RefreshResult<TBundle>) => {\n if (res.changed) fn(res as any);\n };\n this.updateListeners.push(wrapped);\n return () => {\n this.updateListeners = this.updateListeners.filter((x) => x !== wrapped);\n };\n }\n\n /** Subscribe to status changes (ok/degraded). */\n onStatus(fn: (s: RuntimeStatus) => void) {\n this.statusListeners.push(fn);\n fn(this.getStatus());\n return () => {\n this.statusListeners = this.statusListeners.filter((x) => x !== fn);\n };\n }\n\n /** Evaluate a decision using the cached bundle (deny-by-default if bundle missing/invalid). */\n evaluate(input: { target: Target; context?: Record<string, unknown> }): Decision {\n return this.engine.evaluate(input);\n }\n\n /** Evaluate and (optionally) attach trace based on trace defaults/overrides. */\n evaluateWithTrace(\n input: { target: Target; context?: Record<string, unknown> },\n options?: TraceOptions\n ): DecisionWithOptionalTrace {\n return this.engine.evaluateWithTrace(input, options);\n }\n\n /** Flush async trace queue (only does something if traceSinkAsync is configured). */\n flushTraces(): Promise<void> {\n return this.engine.flushTraces();\n }\n\n getCached(): RuntimeCache<TBundle> {\n return { ...this.cache };\n }\n\n getStatus(): RuntimeStatus {\n // si aún no hemos cacheado un bundle válido, es warming_up\n const b: any = this.cache.bundle;\n const valid = !!(b && typeof b === \"object\" && b.schemaVersion === 1 && Array.isArray(b.policies));\n if (!this.hasValidBundle && !valid) return { state: \"warming_up\" };\n\n if (this.consecutiveFailures >= this.cfg.degradeAfterFailures) {\n return {\n state: \"degraded\",\n consecutiveFailures: this.consecutiveFailures,\n lastError: this.lastError ?? { message: \"unknown\", at: new Date().toISOString() },\n nextRetryAt: this.nextRetryAtMs ? new Date(this.nextRetryAtMs).toISOString() : undefined\n };\n }\n return { state: \"ok\" };\n }\n\n start() {\n if (this.isRunning) return;\n this.isRunning = true;\n\n // Incident controls (primero)\n this.applyIncidentFromEnv();\n this.startIncidentFilePoller();\n this.installIncidentSignal();\n\n // Luego el loop\n this.scheduleNext(0);\n }\n\n async warmStart(opts?: { timeoutMs?: number; burst?: boolean }): Promise<void> {\n // Incident controls (por si warmStart se usa sin start)\n this.applyIncidentFromEnv();\n this.startIncidentFilePoller();\n this.installIncidentSignal();\n\n const timeoutMs = opts?.timeoutMs ?? 10_000;\n const until = Date.now() + timeoutMs;\n\n if (opts?.burst) {\n await this.refreshNow({ burst: true }).catch(() => void 0);\n } else {\n await this.refreshNow().catch(() => void 0);\n }\n\n while (Date.now() < until) {\n const b: any = this.cache.bundle;\n const valid = !!(b && typeof b === \"object\" && b.schemaVersion === 1 && Array.isArray(b.policies));\n if (valid) {\n this.hasValidBundle = true;\n return;\n }\n await new Promise((r) => setTimeout(r, 100));\n }\n\n throw new Error(\"warmStart timeout: no valid runtime bundle received\");\n }\n\n stop() {\n this.isRunning = false;\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n\n if (this.incidentPollTimer) clearInterval(this.incidentPollTimer);\n this.incidentPollTimer = null;\n this.uninstallIncidentSignal();\n }\n\n async refreshNow(opts?: { burst?: boolean }): Promise<RefreshResult<TBundle>> {\n if (opts?.burst) {\n this.burstUntil = Date.now() + this.cfg.burstDurationMs;\n if (this.isRunning) this.scheduleNext(0);\n }\n return this.refresh();\n }\n\n private emitStatusIfNeeded(prev: RuntimeStatus) {\n const next = this.getStatus();\n\n const key = (s: RuntimeStatus) => {\n if (s.state === \"warming_up\") return \"warming_up\";\n if (s.state === \"ok\") return \"ok\";\n return `degraded:${s.consecutiveFailures}:${s.lastError.message}`;\n };\n\n if (key(prev) !== key(next)) {\n for (const l of this.statusListeners) l(next);\n }\n }\n \n\n private async refresh(): Promise<RefreshResult<TBundle>> {\n if (this.inFlightRefresh) return this.inFlightRefresh;\n\n const prevStatus = this.getStatus();\n\n this.inFlightRefresh = (async () => {\n try {\n const head = await this.headBundle();\n if (!head) {\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return { changed: false, meta: this.cache.meta };\n }\n\n const prevEtag = this.cache.meta?.etag;\n if (prevEtag && head.etag === prevEtag) {\n this.cache.meta = head;\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return { changed: false, meta: head };\n }\n\n const got = await this.getBundle();\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return got.changed ? got : { changed: false, meta: got.meta };\n } catch (err: any) {\n this.markFailure(err);\n this.emitStatusIfNeeded(prevStatus);\n throw err;\n } finally {\n this.inFlightRefresh = null;\n }\n })();\n\n return this.inFlightRefresh;\n }\n\n private scheduleNext(delayMs: number) {\n if (!this.isRunning) return;\n if (this.timer) clearTimeout(this.timer);\n\n this.timer = setTimeout(async () => {\n const prevStatus = this.getStatus();\n\n try {\n // incident env flag\n this.applyIncidentFromEnv();\n\n // backoff guard (si tienes nextRetryAtMs)\n if (this.nextRetryAtMs && Date.now() < this.nextRetryAtMs) {\n this.scheduleNext(Math.max(0, this.nextRetryAtMs - Date.now()));\n return;\n }\n\n const res = await this.refresh();\n if (res.changed) {\n for (const l of this.updateListeners) l(res);\n }\n } catch {\n // swallow\n } finally {\n this.emitStatusIfNeeded(prevStatus);\n\n const next =\n this.nextRetryAtMs && Date.now() < this.nextRetryAtMs\n ? Math.max(0, this.nextRetryAtMs - Date.now())\n : this.effectivePollMs();\n\n this.scheduleNext(next);\n }\n }, delayMs);\n }\n\n private effectivePollMs() {\n const now = Date.now();\n if (now < this.burstUntil) return this.cfg.burstPollMs;\n return this.cfg.pollMs;\n }\n\n private markSuccess() {\n this.consecutiveFailures = 0;\n this.lastError = null;\n this.nextRetryAtMs = null;\n }\n\n private markFailure(err: any) {\n this.consecutiveFailures += 1;\n this.lastError = { message: String(err?.message ?? err ?? \"unknown\"), at: new Date().toISOString() };\n\n const delay = this.computeBackoffDelayMs(this.consecutiveFailures);\n this.nextRetryAtMs = Date.now() + delay;\n }\n\n private computeBackoffDelayMs(failures: number) {\n const base = this.cfg.backoffBaseMs;\n const max = this.cfg.backoffMaxMs;\n const exp = base * Math.pow(2, Math.max(0, failures - 1));\n const capped = Math.min(max, exp);\n\n const jitter = Math.max(0, Math.min(1, this.cfg.backoffJitter));\n const delta = capped * jitter;\n const min = Math.max(0, capped - delta);\n const maxJ = capped + delta;\n\n const r = Math.random();\n return Math.floor(min + r * (maxJ - min));\n }\n\n private bundleUrl(): string {\n const u = new URL(this.cfg.baseUrl);\n u.pathname = \"/v1/runtime/bundle\";\n u.searchParams.set(\"projectId\", this.cfg.projectId);\n u.searchParams.set(\"env\", this.cfg.env);\n return u.toString();\n }\n\n private commonHeaders(extra?: Record<string, string>) {\n return {\n Authorization: `Bearer ${this.cfg.runtimeKey}`,\n \"User-Agent\": this.cfg.userAgent ?? \"govplane-runtime-sdk/0.x\",\n ...extra\n };\n }\n\n private async headBundle(): Promise<BundleMeta | undefined> {\n const url = this.bundleUrl();\n\n const { statusCode, headers, body } = await request(url, {\n method: \"HEAD\",\n headers: this.commonHeaders(),\n bodyTimeout: this.cfg.timeoutMs,\n headersTimeout: this.cfg.timeoutMs\n });\n\n await body.text().catch(() => void 0);\n\n if (statusCode === 401 || statusCode === 403) throw new Error(`Unauthorized (${statusCode})`);\n if (statusCode >= 500) throw new Error(`Runtime server error (${statusCode})`);\n if (statusCode !== 200 && statusCode !== 304) return this.cache.meta;\n\n const etag = (headers[\"etag\"] as string | undefined) ?? \"\";\n if (!etag) return this.cache.meta;\n\n const bundleVersionRaw = headers[\"x-gp-bundle-version\"] as string | undefined;\n const updatedAt = headers[\"x-gp-updated-at\"] as string | undefined;\n\n return {\n etag,\n bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined,\n updatedAt\n };\n }\n\n private async getBundle(): Promise<RefreshResult<TBundle>> {\n const url = this.bundleUrl();\n const ifNoneMatch = this.cache.meta?.etag;\n\n const { statusCode, headers, body } = await request(url, {\n method: \"GET\",\n headers: this.commonHeaders(ifNoneMatch ? { \"If-None-Match\": ifNoneMatch } : undefined),\n bodyTimeout: this.cfg.timeoutMs,\n headersTimeout: this.cfg.timeoutMs\n });\n\n const txt = await body.text();\n\n if (statusCode === 304) {\n const etag = (headers[\"etag\"] as string | undefined) ?? ifNoneMatch ?? \"\";\n const bundleVersionRaw = headers[\"x-gp-bundle-version\"] as string | undefined;\n const updatedAt = headers[\"x-gp-updated-at\"] as string | undefined;\n\n const meta: BundleMeta | undefined = etag\n ? { etag, bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined, updatedAt }\n : this.cache.meta;\n\n if (meta) this.cache.meta = meta;\n return { changed: false, meta };\n }\n\n if (statusCode === 401 || statusCode === 403) throw new Error(`Unauthorized (${statusCode})`);\n if (statusCode >= 400) throw new Error(`Runtime HTTP error (${statusCode}): ${txt.slice(0, 200)}`);\n\n const etag = (headers[\"etag\"] as string | undefined) ?? \"\";\n const bundleVersionRaw = headers[\"x-gp-bundle-version\"] as string | undefined;\n const updatedAt = headers[\"x-gp-updated-at\"] as string | undefined;\n\n const meta: BundleMeta = {\n etag: etag || (ifNoneMatch ?? \"\"),\n bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined,\n updatedAt\n };\n\n const parsed = JSON.parse(txt) as any;\n\n // Normaliza: si viene { success, data }, usa data (y si data.body existe, usa data.body)\n const normalized =\n parsed?.schemaVersion === 1\n ? parsed\n : parsed?.data?.schemaVersion === 1\n ? parsed.data\n : parsed?.data?.body?.schemaVersion === 1\n ? parsed.data.body\n : parsed?.body?.schemaVersion === 1\n ? parsed.body\n : parsed;\n\n this.cache = { meta, bundle: normalized as TBundle };\n\n const nb: any = normalized;\n if (nb && typeof nb === \"object\" && nb.schemaVersion === 1 && Array.isArray(nb.policies)) {\n this.hasValidBundle = true;\n }\n\n return { changed: true, meta, bundle: normalized as TBundle };\n }\n\n // Incident controls\n private enableBurst(input: { durationMs: number; pollMs: number }) {\n const now = Date.now();\n const until = now + Math.max(0, input.durationMs);\n if (until > this.burstUntil) this.burstUntil = until;\n\n // allow runtime tuning for incident\n if (Number.isFinite(input.pollMs) && input.pollMs > 0) {\n (this.cfg as any).burstPollMs = input.pollMs;\n }\n\n console.log(`[govplane][incident] burst enabled until ${new Date(this.burstUntil).toISOString()} (pollMs=${this.cfg.burstPollMs})`);\n }\n\n private disableBurst() {\n this.burstUntil = 0;\n console.log(`[govplane][incident] burst disabled`);\n }\n\n private applyIncidentFromEnv() {\n const flag = this.cfg.incidentEnvFlag;\n if (!flag) return;\n\n const v = String(process.env[flag] ?? \"\").trim().toLowerCase();\n const on = v === \"1\" || v === \"true\" || v === \"yes\" || v === \"on\";\n\n if (on) {\n this.enableBurst({ durationMs: this.cfg.burstDurationMs, pollMs: this.cfg.burstPollMs });\n }\n\n }\n\n private startIncidentFilePoller() {\n const filePath = this.cfg.incidentFilePath;\n if (!filePath) return;\n\n if (this.incidentPollTimer) clearInterval(this.incidentPollTimer);\n\n this.incidentPollTimer = setInterval(() => {\n void this.checkIncidentFileOnce(filePath).catch(() => void 0);\n }, this.cfg.incidentFilePollMs);\n\n // run once immediately\n void this.checkIncidentFileOnce(filePath).catch(() => void 0);\n }\n\n private async checkIncidentFileOnce(filePath: string) {\n // stat: if missing, ignore\n let mtimeMs: number;\n try {\n const st = await fsp.stat(filePath);\n mtimeMs = st.mtimeMs;\n } catch {\n // file missing\n return;\n }\n\n if (this.incidentFileLastMtimeMs !== null && mtimeMs === this.incidentFileLastMtimeMs) return;\n this.incidentFileLastMtimeMs = mtimeMs;\n\n let txt: string;\n try {\n txt = await fsp.readFile(filePath, \"utf8\");\n } catch {\n return;\n }\n\n let payload: IncidentFilePayload;\n try {\n payload = JSON.parse(txt);\n } catch {\n return;\n }\n if (!payload || typeof payload !== \"object\") return;\n\n if (payload.burst === true) {\n this.enableBurst({\n durationMs: payload.burstDurationMs ?? this.cfg.burstDurationMs,\n pollMs: payload.burstPollMs ?? this.cfg.burstPollMs\n });\n\n if (this.isRunning) this.scheduleNext(0);\n } else if (payload.burst === false) {\n this.disableBurst();\n }\n\n if (payload.refreshNow === true) {\n void this.refreshNow({ burst: payload.burst === true }).catch(() => void 0);\n }\n }\n\n private installIncidentSignal() {\n if (this.installedSignalHandler) return;\n if (this.cfg.incidentSignal === false) return;\n\n const sig = this.cfg.incidentSignal;\n\n if(!sig) return;\n\n try {\n this.sigHandler = () => {\n this.enableBurst({ durationMs: this.cfg.burstDurationMs, pollMs: this.cfg.burstPollMs });\n if (this.isRunning) this.scheduleNext(0);\n void this.refreshNow({ burst: true }).catch(() => void 0);\n };\n\n process.on(sig, this.sigHandler);\n this.installedSignalHandler = true;\n } catch {\n // ignore unsupported environments\n }\n }\n\n private uninstallIncidentSignal() {\n if (!this.installedSignalHandler) return;\n if (this.cfg.incidentSignal === false) return;\n\n const sig = this.cfg.incidentSignal;\n\n if(!sig) return;\n\n try {\n if (this.sigHandler) process.off(sig, this.sigHandler);\n } catch {\n // ignore\n } finally {\n this.installedSignalHandler = false;\n this.sigHandler = undefined;\n }\n }\n}","export type ContextPolicy = {\n allowedKeys: string[];\n maxStringLen: number;\n maxArrayLen: number;\n blockLikelyPiiKeys: boolean;\n};\n\nexport const DEFAULT_CONTEXT_POLICY: ContextPolicy = {\n allowedKeys: [\n \"ctx.plan\",\n \"ctx.country\",\n \"ctx.requestTier\",\n \"ctx.feature\",\n \"ctx.amount\",\n \"ctx.isAuthenticated\",\n \"ctx.role\"\n ],\n maxStringLen: 64,\n maxArrayLen: 10,\n blockLikelyPiiKeys: true\n};\n\n// Heurística simple (no perfecta): bloquea nombres de claves típicas de PII\nconst PII_KEY_PATTERNS: RegExp[] = [\n /email/i,\n /phone/i,\n /mobile/i,\n /name/i,\n /firstname/i,\n /lastname/i,\n /address/i,\n /street/i,\n /postcode|postal/i,\n /city/i,\n /ip/i,\n /ssn/i,\n /dni|nie/i,\n /passport/i\n];\n\nconst DEFAULT_POLICY: Required<Omit<ContextPolicy, \"allowedKeys\">> = {\n maxStringLen: 80,\n maxArrayLen: 25,\n blockLikelyPiiKeys: true\n};\n\nexport function validateContext(\n ctx: Record<string, unknown>,\n policy: ContextPolicy\n): void {\n const allowed = new Set(policy.allowedKeys);\n const maxStringLen = policy.maxStringLen ?? DEFAULT_POLICY.maxStringLen;\n const maxArrayLen = policy.maxArrayLen ?? DEFAULT_POLICY.maxArrayLen;\n const blockLikelyPiiKeys = policy.blockLikelyPiiKeys ?? DEFAULT_POLICY.blockLikelyPiiKeys;\n\n for (const [k, v] of Object.entries(ctx)) {\n const path = `ctx.${k}`;\n\n if (!allowed.has(path)) {\n throw new Error(`Context key not allowed: ${path}`);\n }\n\n if (blockLikelyPiiKeys) {\n for (const re of PII_KEY_PATTERNS) {\n if (re.test(k)) {\n throw new Error(`Context key looks like PII and is blocked: ${path}`);\n }\n }\n }\n\n if (v === null || v === undefined) continue;\n\n const t = typeof v;\n if (t === \"boolean\" || t === \"number\") continue;\n\n if (t === \"string\") {\n if ((v as string).length > maxStringLen) throw new Error(`Context value too long: ${path}`);\n continue;\n }\n\n if (Array.isArray(v)) {\n if (v.length > maxArrayLen) throw new Error(`Context array too long: ${path}`);\n for (const it of v) {\n if (typeof it !== \"string\") throw new Error(`Invalid array value type: ${path}`);\n if (it.length > maxStringLen) throw new Error(`Invalid array value length: ${path}`);\n }\n continue;\n }\n\n throw new Error(`Invalid context type for ${path}`);\n }\n}","import type { WhenAstV1 } from \"./types.js\";\n\nfunction getPath(obj: any, path: string): any {\n // path esperado: \"ctx.xxx\"\n const parts = path.split(\".\");\n let cur = obj;\n for (const p of parts) {\n if (!cur || typeof cur !== \"object\") return undefined;\n cur = cur[p];\n }\n return cur;\n}\n\nexport function evalWhen(node: WhenAstV1, ctx: Record<string, unknown>): boolean {\n switch (node.op) {\n case \"and\": return node.args.every(n => evalWhen(n, ctx));\n case \"or\": return node.args.some(n => evalWhen(n, ctx));\n case \"not\": return !evalWhen(node.arg, ctx);\n\n case \"exists\": return getPath({ ctx }, node.path) !== undefined;\n\n case \"in\": {\n const v = getPath({ ctx }, node.path);\n return node.values.some(x => x === v);\n }\n\n case \"eq\": return getPath({ ctx }, node.path) === node.value;\n case \"ne\": return getPath({ ctx }, node.path) !== node.value;\n\n case \"gt\": return Number(getPath({ ctx }, node.path)) > Number(node.value);\n case \"gte\": return Number(getPath({ ctx }, node.path)) >= Number(node.value);\n case \"lt\": return Number(getPath({ ctx }, node.path)) < Number(node.value);\n case \"lte\": return Number(getPath({ ctx }, node.path)) <= Number(node.value);\n\n default:\n return false;\n }\n}","import type { StructuredTraceEvent, TraceSinkAsync, TraceQueueDropPolicy } from \"./types\";\n\ntype Opts = {\n sinkAsync: TraceSinkAsync;\n max: number;\n dropPolicy: TraceQueueDropPolicy;\n onError?: (err: unknown) => void;\n};\n\nexport class TraceDispatcher {\n private q: StructuredTraceEvent[] = [];\n private draining = false;\n\n private flushWaiters: Array<() => void> = [];\n\n constructor(private readonly opts: Opts) {}\n\n enqueue(evt: StructuredTraceEvent): void {\n if (this.q.length >= this.opts.max) {\n if (this.opts.dropPolicy === \"drop_old\") {\n this.q.shift();\n } else {\n return;\n }\n }\n\n this.q.push(evt);\n this.kick();\n }\n\n async flush(): Promise<void> {\n if (!this.draining && this.q.length === 0) return;\n\n return new Promise<void>((resolve) => {\n this.flushWaiters.push(resolve);\n this.kick();\n });\n }\n\n private kick(): void {\n if (this.draining) return;\n if (this.q.length === 0) {\n this.resolveFlushWaitersIfIdle();\n return;\n }\n\n this.draining = true;\n\n // Non-blocking drain\n queueMicrotask(() => void this.drain());\n }\n\n private resolveFlushWaitersIfIdle(): void {\n if (this.draining) return;\n if (this.q.length !== 0) return;\n\n const waiters = this.flushWaiters;\n this.flushWaiters = [];\n for (const w of waiters) w();\n }\n\n private async drain(): Promise<void> {\n try {\n while (this.q.length) {\n const evt = this.q.shift()!;\n try {\n await this.opts.sinkAsync(evt);\n } catch (err) {\n if (this.opts.onError) this.opts.onError(err);\n }\n }\n } finally {\n this.draining = false;\n // resolve flush waiters if idle now\n this.resolveFlushWaitersIfIdle();\n // if items arrived during finishing, restart\n if (this.q.length) this.kick();\n }\n }\n}","import type { Decision } from \"./types\";\nimport type { DecisionTraceCompact, DecisionTraceFull, StructuredTraceEvent, TraceLevel } from \"./types\";\n\nexport function toStructuredTraceEvent(input: {\n level: TraceLevel;\n decision: Decision;\n trace: DecisionTraceCompact | DecisionTraceFull;\n}): StructuredTraceEvent {\n const { decision, trace, level } = input;\n\n const evt: StructuredTraceEvent = {\n v: 1,\n ts: trace.evaluatedAt,\n traceId: trace.traceId,\n sampled: trace.sampled,\n level,\n target: trace.target,\n decision: decision.decision,\n reason: decision.reason,\n winner: trace.winner,\n summary: trace.summary\n };\n\n if (level === \"full\" && \"rules\" in trace) {\n evt.rules = trace.rules.map(r => ({\n policyKey: r.policyKey,\n ruleId: r.ruleId,\n priority: r.priority,\n effectType: r.effectType,\n matched: r.matched,\n discardedReason: r.discardedReason\n }));\n }\n\n return evt;\n}","import type { Decision } from \"./types\";\nimport type {\n DecisionTraceCompact,\n DecisionTraceFull,\n StructuredTraceEvent,\n TraceLevel,\n TraceSink\n} from \"./types\";\nimport { toStructuredTraceEvent } from \"./toStructuredTrace\";\nimport type { TraceDispatcher } from \"./traceDispatcher\";\n\nexport function emitTraceIfAny(input: {\n level: TraceLevel;\n decision: Decision;\n trace?: DecisionTraceCompact | DecisionTraceFull;\n\n sink?: TraceSink;\n dispatcher?: TraceDispatcher;\n\n onSinkError?: (err: unknown) => void;\n}): void {\n const { trace, decision, level } = input;\n if (!trace) return;\n\n let evt: StructuredTraceEvent;\n try {\n evt = toStructuredTraceEvent({ level, decision, trace });\n } catch (err) {\n input.onSinkError?.(err);\n return;\n }\n\n // Sync sink (best-effort)\n if (input.sink) {\n try {\n input.sink(evt);\n } catch (err) {\n input.onSinkError?.(err);\n }\n }\n\n // Async sink via dispatcher (non-blocking)\n if (input.dispatcher) {\n input.dispatcher.enqueue(evt);\n }\n}","import type { Decision, RuntimeBundleV1, Target, PolicyEngine } from \"./types\";\nimport type { ContextPolicy } from \"./context\";\nimport { validateContext, DEFAULT_CONTEXT_POLICY } from \"./context\";\nimport { evalWhen } from \"./when\";\nimport type { TraceOptions, TraceMode, DecisionWithOptionalTrace, TraceSink, TraceSinkAsync, TraceQueueDropPolicy } from \"./types\";\nimport { TraceDispatcher } from \"./traceDispatcher\";\nimport { emitTraceIfAny } from \"./emitTrace\";\n\nfunction clamp01(n: number) {\n if (!Number.isFinite(n)) return 0;\n if (n < 0) return 0;\n if (n > 1) return 1;\n return n;\n}\n\nfunction safeEffectType(effect: any): string | undefined {\n const t = effect?.type;\n return typeof t === \"string\" ? t : undefined;\n}\n\n// UUID v4 (no deps). Node 16+ usually has crypto.randomUUID.\n// Fallback uses randomBytes.\nfunction makeTraceId(): string {\n const g: any = globalThis as any;\n const cryptoAny: any = g.crypto;\n\n if (cryptoAny?.randomUUID) {\n return cryptoAny.randomUUID();\n }\n\n // Node's crypto module fallback (CJS/ESM safe: dynamic require)\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const nodeCrypto = require(\"node:crypto\");\n if (nodeCrypto?.randomUUID) return nodeCrypto.randomUUID();\n const b: Buffer | undefined = nodeCrypto.randomBytes?.(16);\n if (!b || b.length < 16) {\n throw new Error(\"Failed to generate random bytes for UUID\");\n }\n // RFC4122 v4 bits\n if (b) {\n //@ts-ignore\n b[6] = (b[6] & 0x0f) | 0x40;\n //@ts-ignore\n b[8] = (b[8] & 0x3f) | 0x80;\n }\n const hex = b.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n } catch {\n // Last resort (not cryptographically strong, but acceptable for trace correlation)\n return `gp_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;\n }\n}\n\ntype EngineOpts = {\n getBundle: () => RuntimeBundleV1 | undefined;\n\n // default: true\n validateContext?: boolean;\n\n // policy configurable (PII-safe)\n contextPolicy?: ContextPolicy;\n\n // optional: default trace options for evaluateWithTrace()\n traceDefaults?: TraceOptions;\n\n // Event emitter for trace sink\n traceSink?: TraceSink;\n traceSinkAsync?: TraceSinkAsync;\n traceQueueMax?: number; // default 1000\n traceQueueDropPolicy?: TraceQueueDropPolicy; // \"drop_new\" | \"drop_old\"\n onTraceSinkError?: (err: unknown) => void;\n};\n\ntype EvaluateInput = {\n target: Target;\n context?: Record<string, unknown>;\n};\n\ntype Match = {\n policyKey: string;\n ruleId: string;\n priority: number;\n effect: any;\n};\n\nfunction targetMatch(a: Target, b: Target) {\n return a.service === b.service && a.resource === b.resource && a.action === b.action;\n}\n\nfunction byRuleOrder(a: Match, b: Match) {\n // priority desc, policyKey asc, ruleId asc\n const pr = (Number(b.priority) || 0) - (Number(a.priority) || 0);\n if (pr !== 0) return pr;\n const pk = String(a.policyKey).localeCompare(String(b.policyKey));\n if (pk !== 0) return pk;\n return String(a.ruleId).localeCompare(String(b.ruleId));\n}\n\nfunction throttleStrictness(th: { limit: number; windowSeconds: number }) {\n const limit = Number(th?.limit);\n const windowSeconds = Number(th?.windowSeconds);\n const rate = windowSeconds > 0 ? limit / windowSeconds : Number.POSITIVE_INFINITY; // lower => stricter\n return { rate, limit, windowSeconds };\n}\n\n// Simple in-memory budget: N traces per windowMs (default 60/min)\nfunction makeTraceBudget(maxTraces: number, windowMs: number) {\n let windowStart = Date.now();\n let used = 0;\n\n return {\n allow(): boolean {\n const now = Date.now();\n if (now - windowStart >= windowMs) {\n windowStart = now;\n used = 0;\n }\n if (used >= maxTraces) return false;\n used += 1;\n return true;\n }\n };\n}\n\nexport function createPolicyEngine(opts: EngineOpts): PolicyEngine {\n const budget = makeTraceBudget(\n Number.isFinite(opts.traceDefaults?.budget?.maxTraces) ? (opts.traceDefaults!.budget!.maxTraces as number) : 60,\n Number.isFinite(opts.traceDefaults?.budget?.windowMs) ? (opts.traceDefaults!.budget!.windowMs as number) : 60_000\n );\n\n // Initialize trace dispatcher if async sink provided\n const dispatcher =\n opts.traceSinkAsync\n ? new TraceDispatcher({\n sinkAsync: opts.traceSinkAsync,\n max: Number.isFinite(opts.traceQueueMax) ? (opts.traceQueueMax as number) : 1000,\n dropPolicy: opts.traceQueueDropPolicy ?? \"drop_new\",\n onError: opts.onTraceSinkError\n })\n : undefined;\n\n function coreEvaluate(input: EvaluateInput, wantTrace: boolean) {\n const bundle = opts.getBundle();\n const ctx = input.context ?? {};\n\n if (opts.validateContext !== false) {\n validateContext(ctx, opts.contextPolicy ?? DEFAULT_CONTEXT_POLICY);\n }\n\n const traceBase = wantTrace\n ? {\n traceId: makeTraceId(),\n sampled: \"random\" as const, // overwritten if forced\n evaluatedAt: new Date().toISOString(),\n target: input.target,\n summary: {\n policiesSeen: 0,\n rulesSeen: 0,\n matched: 0,\n considered: { kill_switch: 0, deny: 0, throttle: 0, allow: 0 }\n },\n rules: [] as any[]\n }\n : null;\n\n // deny-by-default if bundle missing/invalid\n if (!bundle || bundle.schemaVersion !== 1) {\n const decision: Decision = { decision: \"deny\", reason: \"default\" };\n if (!wantTrace) return decision;\n\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: undefined\n }\n };\n }\n\n const kills: Match[] = [];\n const denies: Match[] = [];\n const throttles: Match[] = [];\n const allows: Match[] = [];\n\n const policies = bundle.policies ?? [];\n if (wantTrace) traceBase!.summary.policiesSeen = policies.length;\n\n for (const p of policies) {\n const policyKey = String((p as any).policyKey ?? \"\");\n const rules = (p as any).rules ?? [];\n\n for (const r of rules) {\n if (wantTrace) traceBase!.summary.rulesSeen += 1;\n\n const ruleId = String(r?.id ?? \"\");\n const priority = Number(r?.priority ?? 0);\n const effectType = safeEffectType(r?.effect);\n\n // disabled\n if (r?.status !== \"active\") {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType,\n matched: false,\n discardedReason: \"disabled\"\n });\n }\n continue;\n }\n\n // target mismatch\n if (!r?.target || !targetMatch(r.target, input.target)) {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType,\n matched: false,\n discardedReason: \"target_mismatch\"\n });\n }\n continue;\n }\n\n // when false\n if (r.when && !evalWhen(r.when, ctx)) {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType,\n matched: false,\n discardedReason: \"when_false\"\n });\n }\n continue;\n }\n\n // invalid effect\n if (!effectType) {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType: undefined,\n matched: false,\n discardedReason: \"invalid_effect\"\n });\n }\n continue;\n }\n\n // matched\n if (wantTrace) {\n traceBase!.summary.matched += 1;\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType,\n matched: true\n });\n }\n\n const m: Match = { policyKey, ruleId, priority, effect: r.effect };\n\n if (effectType === \"kill_switch\") {\n kills.push(m);\n if (wantTrace) traceBase!.summary.considered.kill_switch += 1;\n } else if (effectType === \"deny\") {\n denies.push(m);\n if (wantTrace) traceBase!.summary.considered.deny += 1;\n } else if (effectType === \"throttle\") {\n throttles.push(m);\n if (wantTrace) traceBase!.summary.considered.throttle += 1;\n } else if (effectType === \"allow\") {\n allows.push(m);\n if (wantTrace) traceBase!.summary.considered.allow += 1;\n }\n }\n }\n\n // Precedence: kill_switch > deny > throttle(strictest) > allow > deny-by-default\n if (kills.length) {\n const w = kills.sort(byRuleOrder)[0]!;\n const decision: Decision = {\n decision: \"kill_switch\",\n reason: \"rule\",\n policyKey: w.policyKey,\n ruleId: w.ruleId,\n killSwitch: w.effect.killSwitch\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"kill_switch\", priority: w.priority }\n }\n };\n }\n\n if (denies.length) {\n const w = denies.sort(byRuleOrder)[0]!;\n const decision: Decision = {\n decision: \"deny\",\n reason: \"rule\",\n policyKey: w.policyKey,\n ruleId: w.ruleId\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"deny\", priority: w.priority }\n }\n };\n }\n\n if (throttles.length) {\n const w = throttles\n .sort((a, b) => {\n const A = throttleStrictness(a.effect.throttle);\n const B = throttleStrictness(b.effect.throttle);\n\n // lower rate => stricter\n if (A.rate !== B.rate) return A.rate - B.rate;\n if (A.limit !== B.limit) return A.limit - B.limit;\n if (A.windowSeconds !== B.windowSeconds) return A.windowSeconds - B.windowSeconds;\n return byRuleOrder(a, b);\n })[0]!;\n\n const decision: Decision = {\n decision: \"throttle\",\n reason: \"rule\",\n policyKey: w.policyKey,\n ruleId: w.ruleId,\n throttle: w.effect.throttle\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"throttle\", priority: w.priority }\n }\n };\n }\n\n if (allows.length) {\n const w = allows.sort(byRuleOrder)[0]!;\n const decision: Decision = {\n decision: \"allow\",\n reason: \"rule\",\n policyKey: w.policyKey,\n ruleId: w.ruleId\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"allow\", priority: w.priority }\n }\n };\n }\n\n const decision: Decision = { decision: \"deny\", reason: \"default\" };\n if (!wantTrace) return decision;\n\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: undefined\n }\n };\n }\n\n return {\n evaluate(input: EvaluateInput) {\n return coreEvaluate(input, false) as Decision;\n },\n\n evaluateWithTrace(input: EvaluateInput, options?: TraceOptions): DecisionWithOptionalTrace {\n const merged: TraceOptions = {\n ...(opts.traceDefaults ?? {}),\n ...(options ?? {})\n };\n\n const level = (merged.level ?? \"sampled\") as any;\n const sampling = clamp01(merged.sampling ?? 0.01);\n const force = merged.force === true;\n\n const isOff = level === \"off\";\n const isErrorLevel = level === \"errors\";\n const isFull = level === \"full\";\n const isSampled = level === \"sampled\";\n\n if (isOff) {\n return coreEvaluate(input, false) as any;\n }\n\n // Always compute decision first (no trace)\n const baseDecision: any = coreEvaluate(input, false);\n\n // errors: only trace on deny/kill_switch unless force\n if (isErrorLevel) {\n const isErrDecision = baseDecision.decision === \"deny\" || baseDecision.decision === \"kill_switch\";\n if (!isErrDecision && !force) {\n return baseDecision;\n }\n\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"errors\";\n\n // errors => compact by default\n const { rules: _rules, ...compact } = out.trace ?? {};\n const finalOut = { ...out, trace: compact };\n\n emitTraceIfAny({ level: \"errors\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return finalOut;\n }\n\n // full: always trace (budget unless forced)\n if (isFull) {\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"random\";\n\n emitTraceIfAny({ level: \"full\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return out;\n }\n\n // sampled: sampling + budget (compact)\n if (isSampled) {\n const include = force ? true : Math.random() < sampling;\n if (!include) return baseDecision;\n\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"random\";\n\n const { rules: _rules, ...compact } = out.trace ?? {};\n const finalOut = { ...out, trace: compact };\n\n emitTraceIfAny({ level: \"sampled\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return finalOut;\n }\n\n // fallback: no trace\n return baseDecision;\n },\n flushTraces: async () => {\n if (!dispatcher) return;\n await dispatcher.flush();\n }\n };\n}","export class GovplaneError extends Error {\n constructor(message: string, public readonly code = \"GP_ERROR\", public readonly details?: any) {\n super(message);\n this.name = \"GovplaneError\";\n }\n}\n\nexport class HttpError extends GovplaneError {\n constructor(\n message: string,\n public readonly status: number,\n public readonly headers?: Record<string, string>,\n details?: any\n ) {\n super(message, \"HTTP_ERROR\", details);\n this.name = \"HttpError\";\n }\n}","import type {\n DecisionTraceCompact,\n DecisionTraceFull\n} from \"./types\";\n\ntype FormatOpts = {\n multiline?: boolean; // default: false\n includeDiscarded?: boolean; // only for full traces\n};\n\nexport function formatTrace(\n trace: DecisionTraceCompact | DecisionTraceFull,\n opts: FormatOpts = {}\n): string {\n const lines: string[] = [];\n\n const hdr =\n `[govplane] traceId=${trace.traceId} ` +\n `sampled=${trace.sampled} ` +\n `policies=${trace.summary.policiesSeen} ` +\n `rules=${trace.summary.rulesSeen} ` +\n `matched=${trace.summary.matched}`;\n\n lines.push(hdr);\n\n if (trace.winner) {\n lines.push(\n `winner → policy=${trace.winner.policyKey} ` +\n `rule=${trace.winner.ruleId} ` +\n `effect=${trace.winner.effectType} ` +\n `priority=${trace.winner.priority}`\n );\n } else {\n lines.push(`winner → none (default decision)`);\n }\n\n if (\"rules\" in trace && opts.includeDiscarded) {\n const discarded = trace.rules.filter(r => !r.matched);\n\n if (discarded.length) {\n lines.push(`discarded rules:`);\n\n for (const r of discarded) {\n lines.push(\n `- policy=${r.policyKey} ` +\n `rule=${r.ruleId} ` +\n `effect=${r.effectType ?? \"?\"} ` +\n `reason=${r.discardedReason}`\n );\n }\n }\n }\n\n if (opts.multiline) {\n return lines.join(\"\\n\");\n }\n\n return lines.join(\" | \");\n}"],"mappings":"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","names":["decision","etag","bundleVersionRaw","updatedAt","meta","fsp"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/engine/context.ts","../src/engine/when.ts","../src/engine/traceDispatcher.ts","../src/engine/toStructuredTrace.ts","../src/engine/emitTrace.ts","../src/engine/createPolicyEngine.ts","../src/client/RuntimeClient.ts","../src/errors/Errors.ts","../src/engine/formatTrace.ts"],"sourcesContent":["export { RuntimeClient } from \"./client/RuntimeClient\";\nexport type { RuntimeClientConfig, RefreshResult, RuntimeCache, BundleMeta, RuntimeStatus } from \"./client/RuntimeClient\";\nexport * from \"./engine/types\";\nexport * from \"./errors/Errors.js\";\nexport * from \"./engine/context.js\";\nexport { createPolicyEngine } from \"./engine/createPolicyEngine.js\";\nexport { formatTrace } from \"./engine/formatTrace.js\";\n","export type ContextPolicy = {\n allowedKeys: string[];\n maxStringLen: number;\n maxArrayLen: number;\n blockLikelyPiiKeys: boolean;\n};\n\nexport const DEFAULT_CONTEXT_POLICY: ContextPolicy = {\n allowedKeys: [\n \"plan\",\n \"country\",\n \"requestTier\",\n \"feature\",\n \"amount\",\n \"isAuthenticated\",\n \"role\"\n ],\n maxStringLen: 64,\n maxArrayLen: 10,\n blockLikelyPiiKeys: true\n};\n\n// Heurística simple (no perfecta): bloquea nombres de claves típicas de PII\nconst PII_KEY_PATTERNS: RegExp[] = [\n /email/i,\n /phone/i,\n /mobile/i,\n /name/i,\n /firstname/i,\n /lastname/i,\n /address/i,\n /street/i,\n /postcode|postal/i,\n /city/i,\n /ip/i,\n /ssn/i,\n /dni|nie/i,\n /passport/i\n];\n\nconst DEFAULT_POLICY: Required<Omit<ContextPolicy, \"allowedKeys\">> = {\n maxStringLen: 80,\n maxArrayLen: 25,\n blockLikelyPiiKeys: true\n};\n\nexport function validateContext(\n ctx: Record<string, unknown>,\n policy: ContextPolicy\n): void {\n // Normalize allowedKeys: strip optional \"ctx.\" prefix so both \"plan\" and\n // \"ctx.plan\" are accepted interchangeably in the policy configuration.\n const allowed = new Set(policy.allowedKeys.map(k => k.startsWith(\"ctx.\") ? k.slice(4) : k));\n const maxStringLen = policy.maxStringLen ?? DEFAULT_POLICY.maxStringLen;\n const maxArrayLen = policy.maxArrayLen ?? DEFAULT_POLICY.maxArrayLen;\n const blockLikelyPiiKeys = policy.blockLikelyPiiKeys ?? DEFAULT_POLICY.blockLikelyPiiKeys;\n\n for (const [k, v] of Object.entries(ctx)) {\n if (!allowed.has(k)) {\n throw new Error(`Context key not allowed: ${k}`);\n }\n\n if (blockLikelyPiiKeys) {\n for (const re of PII_KEY_PATTERNS) {\n if (re.test(k)) {\n throw new Error(`Context key looks like PII and is blocked: ${k}`);\n }\n }\n }\n\n if (v === null || v === undefined) continue;\n\n const t = typeof v;\n if (t === \"boolean\" || t === \"number\") continue;\n\n if (t === \"string\") {\n if ((v as string).length > maxStringLen) throw new Error(`Context value too long: ${k}`);\n continue;\n }\n\n if (Array.isArray(v)) {\n if (v.length > maxArrayLen) throw new Error(`Context array too long: ${k}`);\n for (const it of v) {\n if (typeof it !== \"string\") throw new Error(`Invalid array value type: ${k}`);\n if (it.length > maxStringLen) throw new Error(`Invalid array value length: ${k}`);\n }\n continue;\n }\n\n throw new Error(`Invalid context type for ${k}`);\n }\n}","import type { WhenAstV1 } from \"./types.js\";\n\n// Normalizes a path by stripping the optional \"ctx.\" prefix, then resolves\n// it against the context object. Both \"plan\" and \"ctx.plan\" are equivalent.\nfunction getPath(ctx: Record<string, unknown>, path: string): any {\n const normalizedPath = path.startsWith(\"ctx.\") ? path.slice(4) : path;\n const parts = normalizedPath.split(\".\");\n let cur: any = ctx;\n for (const p of parts) {\n if (!cur || typeof cur !== \"object\") return undefined;\n cur = cur[p];\n }\n return cur;\n}\n\nexport function evalWhen(node: WhenAstV1, ctx: Record<string, unknown>): boolean {\n switch (node.op) {\n case \"and\": {\n // Support both canonical `conditions` and legacy `args`\n const children = (node as any).conditions ?? (node as any).args ?? [];\n return (children as WhenAstV1[]).every(n => evalWhen(n, ctx));\n }\n case \"or\": {\n const children = (node as any).conditions ?? (node as any).args ?? [];\n return (children as WhenAstV1[]).some(n => evalWhen(n, ctx));\n }\n case \"not\": {\n // Support both canonical `condition` and legacy `arg`\n const child = (node as any).condition ?? (node as any).arg;\n return !evalWhen(child as WhenAstV1, ctx);\n }\n\n case \"exists\": {\n const v = getPath(ctx, node.path);\n return v !== undefined && v !== null;\n }\n\n case \"in\": {\n const v = getPath(ctx, node.path);\n return node.values.some(x => x === v);\n }\n\n case \"eq\": return getPath(ctx, node.path) === node.value;\n // `neq` is the canonical spelling; `ne` is kept for legacy bundles\n case \"neq\":\n case \"ne\": return getPath(ctx, node.path) !== node.value;\n\n case \"gt\": return Number(getPath(ctx, node.path)) > Number(node.value);\n case \"gte\": return Number(getPath(ctx, node.path)) >= Number(node.value);\n case \"lt\": return Number(getPath(ctx, node.path)) < Number(node.value);\n case \"lte\": return Number(getPath(ctx, node.path)) <= Number(node.value);\n\n default:\n return false;\n }\n}","import type { StructuredTraceEvent, TraceSinkAsync, TraceQueueDropPolicy } from \"./types\";\n\ntype Opts = {\n sinkAsync: TraceSinkAsync;\n max: number;\n dropPolicy: TraceQueueDropPolicy;\n onError?: (err: unknown) => void;\n};\n\nexport class TraceDispatcher {\n private q: StructuredTraceEvent[] = [];\n private draining = false;\n\n private flushWaiters: Array<() => void> = [];\n\n constructor(private readonly opts: Opts) {}\n\n enqueue(evt: StructuredTraceEvent): void {\n if (this.q.length >= this.opts.max) {\n if (this.opts.dropPolicy === \"drop_old\") {\n this.q.shift();\n } else {\n return;\n }\n }\n\n this.q.push(evt);\n this.kick();\n }\n\n async flush(): Promise<void> {\n if (!this.draining && this.q.length === 0) return;\n\n return new Promise<void>((resolve) => {\n this.flushWaiters.push(resolve);\n this.kick();\n });\n }\n\n private kick(): void {\n if (this.draining) return;\n if (this.q.length === 0) {\n this.resolveFlushWaitersIfIdle();\n return;\n }\n\n this.draining = true;\n\n // Non-blocking drain\n queueMicrotask(() => void this.drain());\n }\n\n private resolveFlushWaitersIfIdle(): void {\n if (this.draining) return;\n if (this.q.length !== 0) return;\n\n const waiters = this.flushWaiters;\n this.flushWaiters = [];\n for (const w of waiters) w();\n }\n\n private async drain(): Promise<void> {\n try {\n while (this.q.length) {\n const evt = this.q.shift()!;\n try {\n await this.opts.sinkAsync(evt);\n } catch (err) {\n if (this.opts.onError) this.opts.onError(err);\n }\n }\n } finally {\n this.draining = false;\n // resolve flush waiters if idle now\n this.resolveFlushWaitersIfIdle();\n // if items arrived during finishing, restart\n if (this.q.length) this.kick();\n }\n }\n}","import type { Decision } from \"./types\";\nimport type { DecisionTraceCompact, DecisionTraceFull, StructuredTraceEvent, TraceLevel } from \"./types\";\n\nexport function toStructuredTraceEvent(input: {\n level: TraceLevel;\n decision: Decision;\n trace: DecisionTraceCompact | DecisionTraceFull;\n}): StructuredTraceEvent {\n const { decision, trace, level } = input;\n\n const evt: StructuredTraceEvent = {\n v: 1,\n ts: trace.evaluatedAt,\n traceId: trace.traceId,\n sampled: trace.sampled,\n level,\n target: trace.target,\n decision: decision.decision,\n reason: decision.reason,\n winner: trace.winner,\n summary: trace.summary\n };\n\n if (level === \"full\" && \"rules\" in trace) {\n evt.rules = trace.rules.map(r => ({\n policyKey: r.policyKey,\n ruleId: r.ruleId,\n priority: r.priority,\n effectType: r.effectType,\n matched: r.matched,\n discardedReason: r.discardedReason\n }));\n }\n\n return evt;\n}","import type { Decision } from \"./types\";\nimport type {\n DecisionTraceCompact,\n DecisionTraceFull,\n StructuredTraceEvent,\n TraceLevel,\n TraceSink\n} from \"./types\";\nimport { toStructuredTraceEvent } from \"./toStructuredTrace\";\nimport type { TraceDispatcher } from \"./traceDispatcher\";\n\nexport function emitTraceIfAny(input: {\n level: TraceLevel;\n decision: Decision;\n trace?: DecisionTraceCompact | DecisionTraceFull;\n\n sink?: TraceSink;\n dispatcher?: TraceDispatcher;\n\n onSinkError?: (err: unknown) => void;\n}): void {\n const { trace, decision, level } = input;\n if (!trace) return;\n\n let evt: StructuredTraceEvent;\n try {\n evt = toStructuredTraceEvent({ level, decision, trace });\n } catch (err) {\n input.onSinkError?.(err);\n return;\n }\n\n // Sync sink (best-effort)\n if (input.sink) {\n try {\n input.sink(evt);\n } catch (err) {\n input.onSinkError?.(err);\n }\n }\n\n // Async sink via dispatcher (non-blocking)\n if (input.dispatcher) {\n input.dispatcher.enqueue(evt);\n }\n}","import type { Decision, RuntimeBundleV1, Target, PolicyEngine } from \"./types\";\nimport type { ContextPolicy } from \"./context\";\nimport { validateContext, DEFAULT_CONTEXT_POLICY } from \"./context\";\nimport { evalWhen } from \"./when\";\nimport type { TraceOptions, TraceMode, DecisionWithOptionalTrace, TraceSink, TraceSinkAsync, TraceQueueDropPolicy } from \"./types\";\nimport { TraceDispatcher } from \"./traceDispatcher\";\nimport { emitTraceIfAny } from \"./emitTrace\";\n\nfunction clamp01(n: number) {\n if (!Number.isFinite(n)) return 0;\n if (n < 0) return 0;\n if (n > 1) return 1;\n return n;\n}\n\nfunction safeEffectType(effect: any): string | undefined {\n const t = effect?.type;\n return typeof t === \"string\" ? t : undefined;\n}\n\n// UUID v4 (no deps). Node 16+ usually has crypto.randomUUID.\n// Fallback uses randomBytes.\nfunction makeTraceId(): string {\n const g: any = globalThis as any;\n const cryptoAny: any = g.crypto;\n\n if (cryptoAny?.randomUUID) {\n return cryptoAny.randomUUID();\n }\n\n // Node's crypto module fallback (CJS/ESM safe: dynamic require)\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const nodeCrypto = require(\"node:crypto\");\n if (nodeCrypto?.randomUUID) return nodeCrypto.randomUUID();\n const b: Buffer | undefined = nodeCrypto.randomBytes?.(16);\n if (!b || b.length < 16) {\n throw new Error(\"Failed to generate random bytes for UUID\");\n }\n // RFC4122 v4 bits\n if (b) {\n //@ts-ignore\n b[6] = (b[6] & 0x0f) | 0x40;\n //@ts-ignore\n b[8] = (b[8] & 0x3f) | 0x80;\n }\n const hex = b.toString(\"hex\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n } catch {\n // Last resort (not cryptographically strong, but acceptable for trace correlation)\n return `gp_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;\n }\n}\n\ntype EngineOpts = {\n getBundle: () => RuntimeBundleV1 | undefined;\n\n // default: true\n validateContext?: boolean;\n\n // policy configurable (PII-safe)\n contextPolicy?: ContextPolicy;\n\n // optional: default trace options for evaluateWithTrace()\n traceDefaults?: TraceOptions;\n\n // Event emitter for trace sink\n traceSink?: TraceSink;\n traceSinkAsync?: TraceSinkAsync;\n traceQueueMax?: number; // default 1000\n traceQueueDropPolicy?: TraceQueueDropPolicy; // \"drop_new\" | \"drop_old\"\n onTraceSinkError?: (err: unknown) => void;\n\n /**\n * When true, custom effect `value` strings are JSON-parsed and the result\n * is attached as `parsedValue` on the decision. Parsing errors are\n * silently swallowed and `parsedValue` is left undefined.\n */\n parseCustomEffect?: boolean;\n};\n\ntype EvaluateInput = {\n target: Target;\n context?: Record<string, unknown>;\n};\n\ntype Match = {\n policyKey: string;\n ruleId: string;\n priority: number;\n effect: any;\n};\n\nfunction targetMatch(a: Target, b: Target) {\n return a.service === b.service && a.resource === b.resource && a.action === b.action;\n}\n\nfunction byRuleOrder(a: Match, b: Match) {\n // priority desc, policyKey asc, ruleId asc\n const pr = (Number(b.priority) || 0) - (Number(a.priority) || 0);\n if (pr !== 0) return pr;\n const pk = String(a.policyKey).localeCompare(String(b.policyKey));\n if (pk !== 0) return pk;\n return String(a.ruleId).localeCompare(String(b.ruleId));\n}\n\nfunction throttleStrictness(th: { limit: number; windowSeconds: number }) {\n const limit = Number(th?.limit);\n const windowSeconds = Number(th?.windowSeconds);\n const rate = windowSeconds > 0 ? limit / windowSeconds : Number.POSITIVE_INFINITY; // lower => stricter\n return { rate, limit, windowSeconds };\n}\n\n// Simple in-memory budget: N traces per windowMs (default 60/min)\nfunction makeTraceBudget(maxTraces: number, windowMs: number) {\n let windowStart = Date.now();\n let used = 0;\n\n return {\n allow(): boolean {\n const now = Date.now();\n if (now - windowStart >= windowMs) {\n windowStart = now;\n used = 0;\n }\n if (used >= maxTraces) return false;\n used += 1;\n return true;\n }\n };\n}\n\nexport function createPolicyEngine(opts: EngineOpts): PolicyEngine {\n const budget = makeTraceBudget(\n Number.isFinite(opts.traceDefaults?.budget?.maxTraces) ? (opts.traceDefaults!.budget!.maxTraces as number) : 60,\n Number.isFinite(opts.traceDefaults?.budget?.windowMs) ? (opts.traceDefaults!.budget!.windowMs as number) : 60_000\n );\n\n // Initialize trace dispatcher if async sink provided\n const dispatcher =\n opts.traceSinkAsync\n ? new TraceDispatcher({\n sinkAsync: opts.traceSinkAsync,\n max: Number.isFinite(opts.traceQueueMax) ? (opts.traceQueueMax as number) : 1000,\n dropPolicy: opts.traceQueueDropPolicy ?? \"drop_new\",\n onError: opts.onTraceSinkError\n })\n : undefined;\n\n function coreEvaluate(input: EvaluateInput, wantTrace: boolean) {\n const bundle = opts.getBundle();\n const ctx = input.context ?? {};\n\n if (opts.validateContext !== false) {\n validateContext(ctx, opts.contextPolicy ?? DEFAULT_CONTEXT_POLICY);\n }\n\n const traceBase = wantTrace\n ? {\n traceId: makeTraceId(),\n sampled: \"random\" as const, // overwritten if forced\n evaluatedAt: new Date().toISOString(),\n target: input.target,\n summary: {\n policiesSeen: 0,\n rulesSeen: 0,\n matched: 0,\n considered: { kill_switch: 0, deny: 0, throttle: 0, allow: 0, custom: 0 }\n },\n rules: [] as any[]\n }\n : null;\n\n // deny-by-default if bundle missing/invalid\n if (!bundle || bundle.schemaVersion !== 1) {\n const decision: Decision = { decision: \"deny\", reason: \"default\" };\n if (!wantTrace) return decision;\n\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: undefined\n }\n };\n }\n\n const kills: Match[] = [];\n const denies: Match[] = [];\n const throttles: Match[] = [];\n const allows: Match[] = [];\n const customs: Match[] = [];\n\n const policies = bundle.policies ?? [];\n if (wantTrace) traceBase!.summary.policiesSeen = policies.length;\n\n for (const p of policies) {\n const policyKey = String((p as any).policyKey ?? \"\");\n const rules = (p as any).rules ?? [];\n\n // Track whether any rule in this policy produced a match for this target\n let policyHadMatch = false;\n\n for (const r of rules) {\n if (wantTrace) traceBase!.summary.rulesSeen += 1;\n\n const ruleId = String(r?.id ?? \"\");\n const priority = Number(r?.priority ?? 0);\n\n // disabled\n if (r?.status !== \"active\") {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType: safeEffectType(r?.effect),\n matched: false,\n discardedReason: \"disabled\"\n });\n }\n continue;\n }\n\n // target mismatch\n if (!r?.target || !targetMatch(r.target, input.target)) {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType: safeEffectType(r?.effect),\n matched: false,\n discardedReason: \"target_mismatch\"\n });\n }\n continue;\n }\n\n // when evaluation with thenEffect / elseEffect support\n let resolvedEffect: any;\n if (r.when !== undefined) {\n const whenResult = evalWhen(r.when, ctx);\n if (whenResult) {\n // when is true: use thenEffect, falling back to effect\n resolvedEffect = r.thenEffect ?? r.effect;\n } else {\n // when is false: use elseEffect or skip the rule entirely\n if (r.elseEffect) {\n resolvedEffect = r.elseEffect;\n } else {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType: safeEffectType(r?.effect),\n matched: false,\n discardedReason: \"when_false\"\n });\n }\n continue;\n }\n }\n } else {\n resolvedEffect = r.effect;\n }\n\n const effectType = safeEffectType(resolvedEffect);\n\n // invalid effect\n if (!effectType) {\n if (wantTrace) {\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType: undefined,\n matched: false,\n discardedReason: \"invalid_effect\"\n });\n }\n continue;\n }\n\n // matched\n policyHadMatch = true;\n if (wantTrace) {\n traceBase!.summary.matched += 1;\n traceBase!.rules.push({\n policyKey,\n ruleId,\n priority,\n effectType,\n matched: true\n });\n }\n\n const m: Match = { policyKey, ruleId, priority, effect: resolvedEffect };\n\n if (effectType === \"kill_switch\") {\n kills.push(m);\n if (wantTrace) traceBase!.summary.considered.kill_switch += 1;\n } else if (effectType === \"deny\") {\n denies.push(m);\n if (wantTrace) traceBase!.summary.considered.deny += 1;\n } else if (effectType === \"throttle\") {\n throttles.push(m);\n if (wantTrace) traceBase!.summary.considered.throttle += 1;\n } else if (effectType === \"allow\") {\n allows.push(m);\n if (wantTrace) traceBase!.summary.considered.allow += 1;\n } else if (effectType === \"custom\") {\n customs.push(m);\n if (wantTrace) traceBase!.summary.considered.custom += 1;\n }\n }\n\n // ── Per-policy default ─────────────────────────────────────────────────\n // If no rule in this policy produced a match for the given target,\n // apply the policy default as a synthetic lowest-priority match.\n if (!policyHadMatch) {\n const defaults: any = (p as any).defaults;\n if (defaults?.effect) {\n const defEffectType = String(defaults.effect);\n // Build a synthetic Effect object from the defaults descriptor\n let syntheticEffect: any;\n if (defEffectType === \"custom\") {\n syntheticEffect = { type: \"custom\", value: String(defaults.customEffect ?? \"\") };\n } else if (defEffectType === \"throttle\" && defaults.throttle) {\n syntheticEffect = { type: \"throttle\", throttle: defaults.throttle };\n } else if (defEffectType === \"kill_switch\" && defaults.killSwitch) {\n syntheticEffect = { type: \"kill_switch\", killSwitch: defaults.killSwitch };\n } else if (defEffectType === \"allow\" || defEffectType === \"deny\") {\n syntheticEffect = { type: defEffectType };\n }\n\n if (syntheticEffect) {\n // Default matches are given priority -1 so explicit rules always win\n const dm: Match = { policyKey, ruleId: \"__default__\", priority: -1, effect: syntheticEffect };\n if (defEffectType === \"kill_switch\") {\n kills.push(dm);\n if (wantTrace) traceBase!.summary.considered.kill_switch += 1;\n } else if (defEffectType === \"deny\") {\n denies.push(dm);\n if (wantTrace) traceBase!.summary.considered.deny += 1;\n } else if (defEffectType === \"throttle\") {\n throttles.push(dm);\n if (wantTrace) traceBase!.summary.considered.throttle += 1;\n } else if (defEffectType === \"allow\") {\n allows.push(dm);\n if (wantTrace) traceBase!.summary.considered.allow += 1;\n } else if (defEffectType === \"custom\") {\n customs.push(dm);\n if (wantTrace) traceBase!.summary.considered.custom += 1;\n }\n }\n }\n }\n }\n\n // Precedence: kill_switch > deny > throttle(strictest) > allow > custom > deny-by-default\n if (kills.length) {\n const w = kills.sort(byRuleOrder)[0]!;\n const isDefault = w.ruleId === \"__default__\";\n const decision: Decision = {\n decision: \"kill_switch\",\n reason: isDefault ? \"default\" : \"rule\",\n policyKey: w.policyKey,\n ruleId: isDefault ? undefined : w.ruleId,\n killSwitch: w.effect.killSwitch\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"kill_switch\", priority: w.priority }\n }\n };\n }\n\n if (denies.length) {\n const w = denies.sort(byRuleOrder)[0]!;\n const isDefault = w.ruleId === \"__default__\";\n const decision: Decision = {\n decision: \"deny\",\n reason: isDefault ? \"default\" : \"rule\",\n policyKey: w.policyKey,\n ruleId: isDefault ? undefined : w.ruleId\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"deny\", priority: w.priority }\n }\n };\n }\n\n if (throttles.length) {\n const w = throttles\n .sort((a, b) => {\n const A = throttleStrictness(a.effect.throttle);\n const B = throttleStrictness(b.effect.throttle);\n\n // lower rate => stricter\n if (A.rate !== B.rate) return A.rate - B.rate;\n if (A.limit !== B.limit) return A.limit - B.limit;\n if (A.windowSeconds !== B.windowSeconds) return A.windowSeconds - B.windowSeconds;\n return byRuleOrder(a, b);\n })[0]!;\n\n const isDefault = w.ruleId === \"__default__\";\n const decision: Decision = {\n decision: \"throttle\",\n reason: isDefault ? \"default\" : \"rule\",\n policyKey: w.policyKey,\n ruleId: isDefault ? undefined : w.ruleId,\n throttle: w.effect.throttle\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"throttle\", priority: w.priority }\n }\n };\n }\n\n if (allows.length) {\n const w = allows.sort(byRuleOrder)[0]!;\n const isDefault = w.ruleId === \"__default__\";\n const decision: Decision = {\n decision: \"allow\",\n reason: isDefault ? \"default\" : \"rule\",\n policyKey: w.policyKey,\n ruleId: isDefault ? undefined : w.ruleId\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"allow\", priority: w.priority }\n }\n };\n }\n\n // custom: lower precedence than allow, higher than deny-by-default\n if (customs.length) {\n const w = customs.sort(byRuleOrder)[0]!;\n const isDefault = w.ruleId === \"__default__\";\n const rawValue = String(w.effect.value ?? \"\");\n let parsedValue: unknown;\n if (opts.parseCustomEffect) {\n try { parsedValue = JSON.parse(rawValue); } catch { /* invalid JSON – leave undefined */ }\n }\n const decision: Decision = {\n decision: \"custom\",\n reason: isDefault ? \"default\" : \"rule\",\n policyKey: w.policyKey,\n ruleId: isDefault ? undefined : w.ruleId,\n value: rawValue,\n ...(parsedValue !== undefined ? { parsedValue } : {})\n };\n\n if (!wantTrace) return decision;\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: { policyKey: w.policyKey, ruleId: w.ruleId, effectType: \"custom\", priority: w.priority }\n }\n };\n }\n\n const decision: Decision = { decision: \"deny\", reason: \"default\" };\n if (!wantTrace) return decision;\n\n return {\n ...decision,\n trace: {\n ...traceBase!,\n winner: undefined\n }\n };\n }\n\n return {\n evaluate(input: EvaluateInput) {\n return coreEvaluate(input, false) as Decision;\n },\n\n evaluateWithTrace(input: EvaluateInput, options?: TraceOptions): DecisionWithOptionalTrace {\n const merged: TraceOptions = {\n ...(opts.traceDefaults ?? {}),\n ...(options ?? {})\n };\n\n const level = (merged.level ?? \"sampled\") as any;\n const sampling = clamp01(merged.sampling ?? 0.01);\n const force = merged.force === true;\n\n const isOff = level === \"off\";\n const isErrorLevel = level === \"errors\";\n const isFull = level === \"full\";\n const isSampled = level === \"sampled\";\n\n if (isOff) {\n return coreEvaluate(input, false) as any;\n }\n\n // Always compute decision first (no trace)\n const baseDecision: any = coreEvaluate(input, false);\n\n // errors: only trace on deny/kill_switch unless force\n if (isErrorLevel) {\n const isErrDecision = baseDecision.decision === \"deny\" || baseDecision.decision === \"kill_switch\";\n if (!isErrDecision && !force) {\n return baseDecision;\n }\n\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"errors\";\n\n // errors => compact by default\n const { rules: _rules, ...compact } = out.trace ?? {};\n const finalOut = { ...out, trace: compact };\n\n emitTraceIfAny({ level: \"errors\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return finalOut;\n }\n\n // full: always trace (budget unless forced)\n if (isFull) {\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"random\";\n\n emitTraceIfAny({ level: \"full\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return out;\n }\n\n // sampled: sampling + budget (compact)\n if (isSampled) {\n const include = force ? true : Math.random() < sampling;\n if (!include) return baseDecision;\n\n if (!force) {\n const ok = budget.allow();\n if (!ok) return baseDecision;\n }\n\n const out: any = coreEvaluate(input, true);\n if (out?.trace) out.trace.sampled = force ? \"forced\" : \"random\";\n\n const { rules: _rules, ...compact } = out.trace ?? {};\n const finalOut = { ...out, trace: compact };\n\n emitTraceIfAny({ level: \"sampled\", decision: out, trace: out.trace, sink: opts.traceSink, dispatcher, onSinkError: opts.onTraceSinkError });\n\n return finalOut;\n }\n\n // fallback: no trace\n return baseDecision;\n },\n flushTraces: async () => {\n if (!dispatcher) return;\n await dispatcher.flush();\n }\n };\n}","import { createPolicyEngine } from \"../engine/createPolicyEngine\";\nimport { promises as fsp } from \"node:fs\";\nimport type {\n RuntimeBundleV1,\n Decision,\n DecisionWithOptionalTrace,\n Target,\n TraceOptions,\n StructuredTraceEvent\n} from \"../engine/types\";\nimport type { ContextPolicy } from \"../engine/context\";\nimport type { PolicyEngine } from \"../engine/types\";\n\nexport type RuntimeClientConfig = {\n baseUrl: string;\n runtimeKey: string;\n // polling\n pollMs?: number; // default 5000\n burstPollMs?: number; // default 500\n burstDurationMs?: number; // default 30000\n\n timeoutMs?: number; // default 5000\n userAgent?: string;\n\n // backoff (Phase 0+)\n backoffBaseMs?: number; // default 500\n backoffMaxMs?: number; // default 30000\n backoffJitter?: number; // default 0.2 (±20%)\n degradeAfterFailures?: number; // default 3\n\n /**\n * Engine config\n */\n engine?: {\n validateContext?: boolean; // default true\n contextPolicy?: ContextPolicy;\n /**\n * When true, custom-effect `value` strings are JSON-parsed and the result\n * is attached as `parsedValue` on the returned decision.\n */\n parseCustomEffect?: boolean;\n };\n\n /**\n * Decision trace (SDK-only, zero PII)\n */\n trace?: {\n defaults?: TraceOptions; // level/sampling/budget/force\n onDecisionTrace?: (evt: StructuredTraceEvent) => void; // sync\n onDecisionTraceAsync?: (evt: StructuredTraceEvent) => Promise<void>; // async\n queueMax?: number; // default 1000\n dropPolicy?: \"drop_new\" | \"drop_old\"; // default drop_new\n onTraceError?: (err: unknown) => void;\n };\n\n // Incident controls (no endpoints)\n incidentEnvFlag?: string; // default \"GP_RUNTIME_INCIDENT\"\n incidentFilePath?: string; // e.g. \"/etc/govplane/incident.json\"\n incidentFilePollMs?: number; // default 1000\n incidentSignal?: \"SIGUSR1\" | false; // default \"SIGUSR1\"\n};\n\nexport type BundleMeta = {\n etag: string;\n bundleVersion?: number;\n updatedAt?: string;\n};\n\nexport type RuntimeCache<TBundle = unknown> = {\n meta?: BundleMeta;\n bundle?: TBundle;\n};\n\nexport type RefreshResult<TBundle = unknown> =\n | { changed: false; meta?: BundleMeta }\n | { changed: true; meta: BundleMeta; bundle: TBundle };\n\nexport type RuntimeStatus =\n | { state: \"warming_up\" }\n | { state: \"ok\" }\n | {\n state: \"degraded\";\n consecutiveFailures: number;\n lastError: { message: string; at: string };\n nextRetryAt?: string;\n };\n\ntype RequiredCfg =\n Required<\n Pick<\n RuntimeClientConfig,\n | \"pollMs\"\n | \"burstPollMs\"\n | \"burstDurationMs\"\n | \"timeoutMs\"\n | \"backoffBaseMs\"\n | \"backoffMaxMs\"\n | \"backoffJitter\"\n | \"degradeAfterFailures\"\n >\n > &\n Omit<\n RuntimeClientConfig,\n | \"pollMs\"\n | \"burstPollMs\"\n | \"burstDurationMs\"\n | \"timeoutMs\"\n | \"backoffBaseMs\"\n | \"backoffMaxMs\"\n | \"backoffJitter\"\n | \"degradeAfterFailures\"\n >;\n\n type IncidentFilePayload = {\n burst?: boolean;\n burstDurationMs?: number;\n burstPollMs?: number;\n refreshNow?: boolean;\n };\n\n/**\n * RuntimeClient = polling/backoff/degraded + cached runtime bundle + policy evaluation.\n *\n * - No endpoints expuestos por el cliente\n * - No PII en trace: el engine emite StructuredTraceEvent sin context ni reglas completas\n */\nexport class RuntimeClient<TBundle = RuntimeBundleV1> {\n private readonly cfg: RequiredCfg;\n\n private cache: RuntimeCache<TBundle> = {};\n private timer: NodeJS.Timeout | null = null;\n private isRunning = false;\n private hasValidBundle = false;\n\n private inFlightRefresh: Promise<RefreshResult<TBundle>> | null = null;\n private burstUntil = 0;\n\n // health / degraded state\n private consecutiveFailures = 0;\n private lastError: { message: string; at: string } | null = null;\n private nextRetryAtMs: number | null = null;\n\n private updateListeners: Array<(res: RefreshResult<TBundle>) => void> = [];\n private statusListeners: Array<(s: RuntimeStatus) => void> = [];\n\n // Policy engine\n private readonly engine: PolicyEngine;\n\n // Incident controls\n private incidentPollTimer: NodeJS.Timeout | null = null;\n private incidentFileLastMtimeMs: number | null = null;\n private installedSignalHandler = false;\n private sigHandler?: () => void;\n\n constructor(config: RuntimeClientConfig) {\n\n console.log(\"[RuntimeClient] initializing with config\");\n\n this.cfg = {\n ...config,\n pollMs: config.pollMs ?? 5000,\n burstPollMs: config.burstPollMs ?? 500,\n burstDurationMs: config.burstDurationMs ?? 30_000,\n timeoutMs: config.timeoutMs ?? 5000,\n\n backoffBaseMs: config.backoffBaseMs ?? 500,\n backoffMaxMs: config.backoffMaxMs ?? 30_000,\n backoffJitter: config.backoffJitter ?? 0.2,\n degradeAfterFailures: config.degradeAfterFailures ?? 3,\n\n incidentEnvFlag: config.incidentEnvFlag ?? \"GP_RUNTIME_INCIDENT\",\n incidentFilePollMs: config.incidentFilePollMs ?? 1000,\n incidentSignal: config.incidentSignal ?? \"SIGUSR1\"\n \n };\n\n // Wiring: el client conecta bundle cacheado + trace sinks + context policy en el engine\n this.engine = createPolicyEngine({\n getBundle: () => this.cache.bundle as any,\n\n validateContext: config.engine?.validateContext !== false,\n contextPolicy: config.engine?.contextPolicy,\n parseCustomEffect: config.engine?.parseCustomEffect,\n\n traceDefaults: config.trace?.defaults,\n traceSink: config.trace?.onDecisionTrace,\n traceSinkAsync: config.trace?.onDecisionTraceAsync,\n traceQueueMax: config.trace?.queueMax,\n traceQueueDropPolicy: config.trace?.dropPolicy,\n onTraceSinkError: config.trace?.onTraceError\n });\n }\n\n /** Subscribe to bundle updates (only when changed). */\n onUpdate(fn: (res: Extract<RefreshResult<TBundle>, { changed: true }>) => void) {\n const wrapped = (res: RefreshResult<TBundle>) => {\n if (res.changed) fn(res as any);\n };\n this.updateListeners.push(wrapped);\n return () => {\n this.updateListeners = this.updateListeners.filter((x) => x !== wrapped);\n };\n }\n\n /** Subscribe to status changes (ok/degraded). */\n onStatus(fn: (s: RuntimeStatus) => void) {\n this.statusListeners.push(fn);\n fn(this.getStatus());\n return () => {\n this.statusListeners = this.statusListeners.filter((x) => x !== fn);\n };\n }\n\n /** Evaluate a decision using the cached bundle (deny-by-default if bundle missing/invalid). */\n evaluate(input: { target: Target; context?: Record<string, unknown> }): Decision {\n return this.engine.evaluate(input);\n }\n\n /** Evaluate and (optionally) attach trace based on trace defaults/overrides. */\n evaluateWithTrace(\n input: { target: Target; context?: Record<string, unknown> },\n options?: TraceOptions\n ): DecisionWithOptionalTrace {\n return this.engine.evaluateWithTrace(input, options);\n }\n\n /** Flush async trace queue (only does something if traceSinkAsync is configured). */\n flushTraces(): Promise<void> {\n return this.engine.flushTraces();\n }\n\n getCached(): RuntimeCache<TBundle> {\n return { ...this.cache };\n }\n\n getStatus(): RuntimeStatus {\n // si aún no hemos cacheado un bundle válido, es warming_up\n const b: any = this.cache.bundle;\n const valid = !!(b && typeof b === \"object\" && b.schemaVersion === 1 && Array.isArray(b.policies));\n if (!this.hasValidBundle && !valid) return { state: \"warming_up\" };\n\n if (this.consecutiveFailures >= this.cfg.degradeAfterFailures) {\n return {\n state: \"degraded\",\n consecutiveFailures: this.consecutiveFailures,\n lastError: this.lastError ?? { message: \"unknown\", at: new Date().toISOString() },\n nextRetryAt: this.nextRetryAtMs ? new Date(this.nextRetryAtMs).toISOString() : undefined\n };\n }\n return { state: \"ok\" };\n }\n\n start() {\n if (this.isRunning) return;\n this.isRunning = true;\n\n // Incident controls (primero)\n this.applyIncidentFromEnv();\n this.startIncidentFilePoller();\n this.installIncidentSignal();\n\n // Luego el loop\n this.scheduleNext(0);\n }\n\n async warmStart(opts?: { timeoutMs?: number; burst?: boolean }): Promise<void> {\n // Incident controls (por si warmStart se usa sin start)\n this.applyIncidentFromEnv();\n this.startIncidentFilePoller();\n this.installIncidentSignal();\n\n const timeoutMs = opts?.timeoutMs ?? 10_000;\n const until = Date.now() + timeoutMs;\n\n if (opts?.burst) {\n await this.refreshNow({ burst: true }).catch(() => void 0);\n } else {\n await this.refreshNow().catch(() => void 0);\n }\n\n while (Date.now() < until) {\n const b: any = this.cache.bundle;\n const valid = !!(b && typeof b === \"object\" && b.schemaVersion === 1 && Array.isArray(b.policies));\n if (valid) {\n this.hasValidBundle = true;\n return;\n }\n await new Promise((r) => setTimeout(r, 100));\n }\n\n throw new Error(\"warmStart timeout: no valid runtime bundle received\");\n }\n\n stop() {\n this.isRunning = false;\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n\n if (this.incidentPollTimer) clearInterval(this.incidentPollTimer);\n this.incidentPollTimer = null;\n this.uninstallIncidentSignal();\n }\n\n async refreshNow(opts?: { burst?: boolean }): Promise<RefreshResult<TBundle>> {\n if (opts?.burst) {\n this.burstUntil = Date.now() + this.cfg.burstDurationMs;\n if (this.isRunning) this.scheduleNext(0);\n }\n return this.refresh();\n }\n\n private emitStatusIfNeeded(prev: RuntimeStatus) {\n const next = this.getStatus();\n\n const key = (s: RuntimeStatus) => {\n if (s.state === \"warming_up\") return \"warming_up\";\n if (s.state === \"ok\") return \"ok\";\n return `degraded:${s.consecutiveFailures}:${s.lastError.message}`;\n };\n\n if (key(prev) !== key(next)) {\n for (const l of this.statusListeners) l(next);\n }\n }\n \n\n private async refresh(): Promise<RefreshResult<TBundle>> {\n if (this.inFlightRefresh) return this.inFlightRefresh;\n\n const prevStatus = this.getStatus();\n\n this.inFlightRefresh = (async () => {\n try {\n const head = await this.headBundle();\n if (!head) {\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return { changed: false, meta: this.cache.meta };\n }\n\n const prevEtag = this.cache.meta?.etag;\n if (prevEtag && head.etag === prevEtag) {\n this.cache.meta = head;\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return { changed: false, meta: head };\n }\n\n const got = await this.getBundle();\n this.markSuccess();\n this.emitStatusIfNeeded(prevStatus);\n return got.changed ? got : { changed: false, meta: got.meta };\n } catch (err: any) {\n this.markFailure(err);\n this.emitStatusIfNeeded(prevStatus);\n throw err;\n } finally {\n this.inFlightRefresh = null;\n }\n })();\n\n return this.inFlightRefresh;\n }\n\n private scheduleNext(delayMs: number) {\n if (!this.isRunning) return;\n if (this.timer) clearTimeout(this.timer);\n\n this.timer = setTimeout(async () => {\n const prevStatus = this.getStatus();\n\n try {\n // incident env flag\n this.applyIncidentFromEnv();\n\n // backoff guard (si tienes nextRetryAtMs)\n if (this.nextRetryAtMs && Date.now() < this.nextRetryAtMs) {\n this.scheduleNext(Math.max(0, this.nextRetryAtMs - Date.now()));\n return;\n }\n\n const res = await this.refresh();\n if (res.changed) {\n for (const l of this.updateListeners) l(res);\n }\n } catch {\n // swallow\n } finally {\n this.emitStatusIfNeeded(prevStatus);\n\n const next =\n this.nextRetryAtMs && Date.now() < this.nextRetryAtMs\n ? Math.max(0, this.nextRetryAtMs - Date.now())\n : this.effectivePollMs();\n\n this.scheduleNext(next);\n }\n }, delayMs);\n }\n\n private effectivePollMs() {\n const now = Date.now();\n if (now < this.burstUntil) return this.cfg.burstPollMs;\n return this.cfg.pollMs;\n }\n\n private markSuccess() {\n this.consecutiveFailures = 0;\n this.lastError = null;\n this.nextRetryAtMs = null;\n }\n\n private markFailure(err: any) {\n this.consecutiveFailures += 1;\n this.lastError = { message: String(err?.message ?? err ?? \"unknown\"), at: new Date().toISOString() };\n\n const delay = this.computeBackoffDelayMs(this.consecutiveFailures);\n this.nextRetryAtMs = Date.now() + delay;\n }\n\n private computeBackoffDelayMs(failures: number) {\n const base = this.cfg.backoffBaseMs;\n const max = this.cfg.backoffMaxMs;\n const exp = base * Math.pow(2, Math.max(0, failures - 1));\n const capped = Math.min(max, exp);\n\n const jitter = Math.max(0, Math.min(1, this.cfg.backoffJitter));\n const delta = capped * jitter;\n const min = Math.max(0, capped - delta);\n const maxJ = capped + delta;\n\n const r = Math.random();\n return Math.floor(min + r * (maxJ - min));\n }\n\n private bundleUrl(): string {\n const u = new URL(this.cfg.baseUrl);\n return u.toString();\n }\n\n private commonHeaders(extra?: Record<string, string>) {\n return {\n Authorization: this.cfg.runtimeKey,\n \"User-Agent\": this.cfg.userAgent ?? \"govplane-runtime-sdk/0.x\",\n ...extra\n };\n }\n\n private async fetchWithTimeout(url: string, init: RequestInit): Promise<Response> {\n const ac = new AbortController();\n const t = setTimeout(() => ac.abort(), this.cfg.timeoutMs);\n try {\n return await fetch(url, { ...init, signal: ac.signal });\n } finally {\n clearTimeout(t);\n }\n }\n\n private async headBundle(): Promise<BundleMeta | undefined> {\n const url = this.bundleUrl();\n const res = await this.fetchWithTimeout(url, {\n method: \"HEAD\",\n headers: this.commonHeaders()\n });\n\n console.log(`[RuntimeClient] HEAD bundle status=${res.status}`);\n\n if (res.status === 401 || res.status === 403) throw new Error(`Unauthorized (${res.status})`);\n if (res.status >= 500) throw new Error(`Runtime server error (${res.status})`);\n if (res.status !== 200 && res.status !== 304) return this.cache.meta;\n\n const etag = res.headers.get(\"etag\") ?? \"\";\n if (!etag) return this.cache.meta;\n\n const bundleVersionRaw = res.headers.get(\"x-gp-bundle-version\") ?? undefined;\n const updatedAt = res.headers.get(\"x-gp-updated-at\") ?? undefined;\n\n return {\n etag,\n bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined,\n updatedAt\n };\n }\n\n private async getBundle(): Promise<RefreshResult<TBundle>> {\n const url = this.bundleUrl();\n const ifNoneMatch = this.cache.meta?.etag;\n\n const res = await this.fetchWithTimeout(url, {\n method: \"GET\",\n headers: this.commonHeaders(ifNoneMatch ? { \"If-None-Match\": ifNoneMatch } : undefined)\n });\n\n const txt = await res.text();\n\n if (res.status === 304) {\n const etag = res.headers.get(\"etag\") ?? ifNoneMatch ?? \"\";\n const bundleVersionRaw = res.headers.get(\"x-gp-bundle-version\") ?? undefined;\n const updatedAt = res.headers.get(\"x-gp-updated-at\") ?? undefined;\n\n const meta: BundleMeta | undefined = etag\n ? { etag, bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined, updatedAt }\n : this.cache.meta;\n\n if (meta) this.cache.meta = meta;\n return { changed: false, meta };\n }\n\n if (res.status === 401 || res.status === 403) throw new Error(`Unauthorized (${res.status})`);\n if (res.status >= 400) throw new Error(`Runtime HTTP error (${res.status}): ${txt.slice(0, 200)}`);\n\n const etag = res.headers.get(\"etag\") ?? \"\";\n const bundleVersionRaw = res.headers.get(\"x-gp-bundle-version\") ?? undefined;\n const updatedAt = res.headers.get(\"x-gp-updated-at\") ?? undefined;\n\n const meta: BundleMeta = {\n etag: etag || (ifNoneMatch ?? \"\"),\n bundleVersion: bundleVersionRaw ? Number(bundleVersionRaw) : undefined,\n updatedAt\n };\n\n const parsed = JSON.parse(txt) as any;\n\n // Normaliza: si viene { success, data }, usa data (y si data.body existe, usa data.body)\n const normalized =\n parsed?.schemaVersion === 1\n ? parsed\n : parsed?.data?.schemaVersion === 1\n ? parsed.data\n : parsed?.data?.body?.schemaVersion === 1\n ? parsed.data.body\n : parsed?.body?.schemaVersion === 1\n ? parsed.body\n : parsed;\n\n this.cache = { meta, bundle: normalized as TBundle };\n\n const nb: any = normalized;\n if (nb && typeof nb === \"object\" && nb.schemaVersion === 1 && Array.isArray(nb.policies)) {\n this.hasValidBundle = true;\n }\n\n return { changed: true, meta, bundle: normalized as TBundle };\n }\n\n // Incident controls\n private enableBurst(input: { durationMs: number; pollMs: number }) {\n const now = Date.now();\n const until = now + Math.max(0, input.durationMs);\n if (until > this.burstUntil) this.burstUntil = until;\n\n // allow runtime tuning for incident\n if (Number.isFinite(input.pollMs) && input.pollMs > 0) {\n (this.cfg as any).burstPollMs = input.pollMs;\n }\n\n console.log(`[govplane][incident] burst enabled until ${new Date(this.burstUntil).toISOString()} (pollMs=${this.cfg.burstPollMs})`);\n }\n\n private disableBurst() {\n this.burstUntil = 0;\n console.log(`[govplane][incident] burst disabled`);\n }\n\n private applyIncidentFromEnv() {\n const flag = this.cfg.incidentEnvFlag;\n if (!flag) return;\n\n const v = String(process.env[flag] ?? \"\").trim().toLowerCase();\n const on = v === \"1\" || v === \"true\" || v === \"yes\" || v === \"on\";\n\n if (on) {\n this.enableBurst({ durationMs: this.cfg.burstDurationMs, pollMs: this.cfg.burstPollMs });\n }\n\n }\n\n private startIncidentFilePoller() {\n const filePath = this.cfg.incidentFilePath;\n if (!filePath) return;\n\n if (this.incidentPollTimer) clearInterval(this.incidentPollTimer);\n\n this.incidentPollTimer = setInterval(() => {\n void this.checkIncidentFileOnce(filePath).catch(() => void 0);\n }, this.cfg.incidentFilePollMs);\n\n // run once immediately\n void this.checkIncidentFileOnce(filePath).catch(() => void 0);\n }\n\n private async checkIncidentFileOnce(filePath: string) {\n // stat: if missing, ignore\n let mtimeMs: number;\n try {\n const st = await fsp.stat(filePath);\n mtimeMs = st.mtimeMs;\n } catch {\n // file missing\n return;\n }\n\n if (this.incidentFileLastMtimeMs !== null && mtimeMs === this.incidentFileLastMtimeMs) return;\n this.incidentFileLastMtimeMs = mtimeMs;\n\n let txt: string;\n try {\n txt = await fsp.readFile(filePath, \"utf8\");\n } catch {\n return;\n }\n\n let payload: IncidentFilePayload;\n try {\n payload = JSON.parse(txt);\n } catch {\n return;\n }\n if (!payload || typeof payload !== \"object\") return;\n\n if (payload.burst === true) {\n this.enableBurst({\n durationMs: payload.burstDurationMs ?? this.cfg.burstDurationMs,\n pollMs: payload.burstPollMs ?? this.cfg.burstPollMs\n });\n\n if (this.isRunning) this.scheduleNext(0);\n } else if (payload.burst === false) {\n this.disableBurst();\n }\n\n if (payload.refreshNow === true) {\n void this.refreshNow({ burst: payload.burst === true }).catch(() => void 0);\n }\n }\n\n private installIncidentSignal() {\n if (this.installedSignalHandler) return;\n if (this.cfg.incidentSignal === false) return;\n\n const sig = this.cfg.incidentSignal;\n\n if(!sig) return;\n\n try {\n this.sigHandler = () => {\n this.enableBurst({ durationMs: this.cfg.burstDurationMs, pollMs: this.cfg.burstPollMs });\n if (this.isRunning) this.scheduleNext(0);\n void this.refreshNow({ burst: true }).catch(() => void 0);\n };\n\n process.on(sig, this.sigHandler);\n this.installedSignalHandler = true;\n } catch {\n // ignore unsupported environments\n }\n }\n\n private uninstallIncidentSignal() {\n if (!this.installedSignalHandler) return;\n if (this.cfg.incidentSignal === false) return;\n\n const sig = this.cfg.incidentSignal;\n\n if(!sig) return;\n\n try {\n if (this.sigHandler) process.off(sig, this.sigHandler);\n } catch {\n // ignore\n } finally {\n this.installedSignalHandler = false;\n this.sigHandler = undefined;\n }\n }\n}","export class GovplaneError extends Error {\n constructor(message: string, public readonly code = \"GP_ERROR\", public readonly details?: any) {\n super(message);\n this.name = \"GovplaneError\";\n }\n}\n\nexport class HttpError extends GovplaneError {\n constructor(\n message: string,\n public readonly status: number,\n public readonly headers?: Record<string, string>,\n details?: any\n ) {\n super(message, \"HTTP_ERROR\", details);\n this.name = \"HttpError\";\n }\n}","import type {\n DecisionTraceCompact,\n DecisionTraceFull\n} from \"./types\";\n\ntype FormatOpts = {\n multiline?: boolean; // default: false\n includeDiscarded?: boolean; // only for full traces\n};\n\nexport function formatTrace(\n trace: DecisionTraceCompact | DecisionTraceFull,\n opts: FormatOpts = {}\n): string {\n const lines: string[] = [];\n\n const hdr =\n `[govplane] traceId=${trace.traceId} ` +\n `sampled=${trace.sampled} ` +\n `policies=${trace.summary.policiesSeen} ` +\n `rules=${trace.summary.rulesSeen} ` +\n `matched=${trace.summary.matched}`;\n\n lines.push(hdr);\n\n if (trace.winner) {\n lines.push(\n `winner → policy=${trace.winner.policyKey} ` +\n `rule=${trace.winner.ruleId} ` +\n `effect=${trace.winner.effectType} ` +\n `priority=${trace.winner.priority}`\n );\n } else {\n lines.push(`winner → none (default decision)`);\n }\n\n if (\"rules\" in trace && opts.includeDiscarded) {\n const discarded = trace.rules.filter(r => !r.matched);\n\n if (discarded.length) {\n lines.push(`discarded rules:`);\n\n for (const r of discarded) {\n lines.push(\n `- policy=${r.policyKey} ` +\n `rule=${r.ruleId} ` +\n `effect=${r.effectType ?? \"?\"} ` +\n `reason=${r.discardedReason}`\n );\n }\n }\n }\n\n if (opts.multiline) {\n return lines.join(\"\\n\");\n }\n\n return lines.join(\" | \");\n}"],"mappings":"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","names":["decision","etag","bundleVersionRaw","updatedAt","meta","fsp"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -20,15 +20,24 @@ type Effect = {
|
|
|
20
20
|
windowSeconds: number;
|
|
21
21
|
key: string;
|
|
22
22
|
};
|
|
23
|
+
} | {
|
|
24
|
+
type: "custom";
|
|
25
|
+
value: string;
|
|
23
26
|
};
|
|
24
27
|
type WhenAstV1 = {
|
|
28
|
+
op: "and" | "or";
|
|
29
|
+
conditions: WhenAstV1[];
|
|
30
|
+
} | {
|
|
25
31
|
op: "and" | "or";
|
|
26
32
|
args: WhenAstV1[];
|
|
33
|
+
} | {
|
|
34
|
+
op: "not";
|
|
35
|
+
condition: WhenAstV1;
|
|
27
36
|
} | {
|
|
28
37
|
op: "not";
|
|
29
38
|
arg: WhenAstV1;
|
|
30
39
|
} | {
|
|
31
|
-
op: "eq" | "ne" | "gt" | "gte" | "lt" | "lte";
|
|
40
|
+
op: "eq" | "neq" | "ne" | "gt" | "gte" | "lt" | "lte";
|
|
32
41
|
path: string;
|
|
33
42
|
value: any;
|
|
34
43
|
} | {
|
|
@@ -45,15 +54,38 @@ type RuntimeRule = {
|
|
|
45
54
|
priority: number;
|
|
46
55
|
target: Target;
|
|
47
56
|
when?: WhenAstV1;
|
|
57
|
+
/** Effect applied when `when` evaluates to true (falls back to `effect`). */
|
|
58
|
+
thenEffect?: Effect;
|
|
59
|
+
/** Effect applied when `when` evaluates to false (rule is skipped if absent). */
|
|
60
|
+
elseEffect?: Effect;
|
|
48
61
|
effect: Effect;
|
|
49
62
|
description?: string;
|
|
50
63
|
};
|
|
64
|
+
type PolicyDefault = {
|
|
65
|
+
effect: "allow";
|
|
66
|
+
} | {
|
|
67
|
+
effect: "deny";
|
|
68
|
+
} | {
|
|
69
|
+
effect: "kill_switch";
|
|
70
|
+
killSwitch: {
|
|
71
|
+
service: string;
|
|
72
|
+
reason?: string;
|
|
73
|
+
};
|
|
74
|
+
} | {
|
|
75
|
+
effect: "throttle";
|
|
76
|
+
throttle: {
|
|
77
|
+
limit: number;
|
|
78
|
+
windowSeconds: number;
|
|
79
|
+
key: string;
|
|
80
|
+
};
|
|
81
|
+
} | {
|
|
82
|
+
effect: "custom";
|
|
83
|
+
customEffect: string;
|
|
84
|
+
};
|
|
51
85
|
type RuntimePolicy = {
|
|
52
86
|
policyKey: string;
|
|
53
87
|
activeVersion: number;
|
|
54
|
-
defaults
|
|
55
|
-
effect: "allow" | "deny";
|
|
56
|
-
};
|
|
88
|
+
defaults?: PolicyDefault;
|
|
57
89
|
rules: RuntimeRule[];
|
|
58
90
|
};
|
|
59
91
|
type RuntimeBundleV1 = {
|
|
@@ -76,23 +108,30 @@ type Decision = {
|
|
|
76
108
|
ruleId?: string;
|
|
77
109
|
} | {
|
|
78
110
|
decision: "kill_switch";
|
|
79
|
-
reason: "rule";
|
|
80
|
-
policyKey
|
|
81
|
-
ruleId
|
|
111
|
+
reason: "default" | "rule";
|
|
112
|
+
policyKey?: string;
|
|
113
|
+
ruleId?: string;
|
|
82
114
|
killSwitch: {
|
|
83
115
|
service: string;
|
|
84
116
|
reason?: string;
|
|
85
117
|
};
|
|
86
118
|
} | {
|
|
87
119
|
decision: "throttle";
|
|
88
|
-
reason: "rule";
|
|
89
|
-
policyKey
|
|
90
|
-
ruleId
|
|
120
|
+
reason: "default" | "rule";
|
|
121
|
+
policyKey?: string;
|
|
122
|
+
ruleId?: string;
|
|
91
123
|
throttle: {
|
|
92
124
|
limit: number;
|
|
93
125
|
windowSeconds: number;
|
|
94
126
|
key: string;
|
|
95
127
|
};
|
|
128
|
+
} | {
|
|
129
|
+
decision: "custom";
|
|
130
|
+
reason: "default" | "rule";
|
|
131
|
+
policyKey?: string;
|
|
132
|
+
ruleId?: string;
|
|
133
|
+
value: string;
|
|
134
|
+
parsedValue?: unknown;
|
|
96
135
|
};
|
|
97
136
|
type TraceDiscardReason = "disabled" | "target_mismatch" | "when_false" | "invalid_effect";
|
|
98
137
|
type TraceRule = {
|
|
@@ -115,6 +154,7 @@ type DecisionTrace = {
|
|
|
115
154
|
deny: number;
|
|
116
155
|
throttle: number;
|
|
117
156
|
allow: number;
|
|
157
|
+
custom: number;
|
|
118
158
|
};
|
|
119
159
|
};
|
|
120
160
|
winner?: {
|
|
@@ -163,6 +203,7 @@ type DecisionTraceCompact = {
|
|
|
163
203
|
deny: number;
|
|
164
204
|
throttle: number;
|
|
165
205
|
allow: number;
|
|
206
|
+
custom: number;
|
|
166
207
|
};
|
|
167
208
|
};
|
|
168
209
|
winner?: {
|
|
@@ -202,6 +243,7 @@ type StructuredTraceEvent = {
|
|
|
202
243
|
deny: number;
|
|
203
244
|
throttle: number;
|
|
204
245
|
allow: number;
|
|
246
|
+
custom: number;
|
|
205
247
|
};
|
|
206
248
|
};
|
|
207
249
|
rules?: Array<{
|
|
@@ -241,9 +283,6 @@ declare function validateContext(ctx: Record<string, unknown>, policy: ContextPo
|
|
|
241
283
|
type RuntimeClientConfig = {
|
|
242
284
|
baseUrl: string;
|
|
243
285
|
runtimeKey: string;
|
|
244
|
-
orgId: string;
|
|
245
|
-
projectId: string;
|
|
246
|
-
env: string;
|
|
247
286
|
pollMs?: number;
|
|
248
287
|
burstPollMs?: number;
|
|
249
288
|
burstDurationMs?: number;
|
|
@@ -259,6 +298,11 @@ type RuntimeClientConfig = {
|
|
|
259
298
|
engine?: {
|
|
260
299
|
validateContext?: boolean;
|
|
261
300
|
contextPolicy?: ContextPolicy;
|
|
301
|
+
/**
|
|
302
|
+
* When true, custom-effect `value` strings are JSON-parsed and the result
|
|
303
|
+
* is attached as `parsedValue` on the returned decision.
|
|
304
|
+
*/
|
|
305
|
+
parseCustomEffect?: boolean;
|
|
262
306
|
};
|
|
263
307
|
/**
|
|
264
308
|
* Decision trace (SDK-only, zero PII)
|
|
@@ -369,6 +413,7 @@ declare class RuntimeClient<TBundle = RuntimeBundleV1> {
|
|
|
369
413
|
private computeBackoffDelayMs;
|
|
370
414
|
private bundleUrl;
|
|
371
415
|
private commonHeaders;
|
|
416
|
+
private fetchWithTimeout;
|
|
372
417
|
private headBundle;
|
|
373
418
|
private getBundle;
|
|
374
419
|
private enableBurst;
|
|
@@ -401,6 +446,12 @@ type EngineOpts = {
|
|
|
401
446
|
traceQueueMax?: number;
|
|
402
447
|
traceQueueDropPolicy?: TraceQueueDropPolicy;
|
|
403
448
|
onTraceSinkError?: (err: unknown) => void;
|
|
449
|
+
/**
|
|
450
|
+
* When true, custom effect `value` strings are JSON-parsed and the result
|
|
451
|
+
* is attached as `parsedValue` on the decision. Parsing errors are
|
|
452
|
+
* silently swallowed and `parsedValue` is left undefined.
|
|
453
|
+
*/
|
|
454
|
+
parseCustomEffect?: boolean;
|
|
404
455
|
};
|
|
405
456
|
declare function createPolicyEngine(opts: EngineOpts): PolicyEngine;
|
|
406
457
|
|
|
@@ -410,4 +461,4 @@ type FormatOpts = {
|
|
|
410
461
|
};
|
|
411
462
|
declare function formatTrace(trace: DecisionTraceCompact | DecisionTraceFull, opts?: FormatOpts): string;
|
|
412
463
|
|
|
413
|
-
export { type BundleMeta, type ContextPolicy, DEFAULT_CONTEXT_POLICY, type Decision, type DecisionTrace, type DecisionTraceCompact, type DecisionTraceFull, type DecisionTraceHook, type DecisionWithOptionalTrace, type DecisionWithTrace, type Effect, GovplaneError, HttpError, type PolicyEngine, type PolicyEngineEvaluateInput, type RefreshResult, type RuntimeBundleV1, type RuntimeCache, RuntimeClient, type RuntimeClientConfig, type RuntimeClientOptions, type RuntimePolicy, type RuntimeRule, type RuntimeStatus, type StructuredTraceEvent, type Target, type TraceDiscardReason, type TraceLevel, type TraceMode, type TraceOptions, type TraceQueueDropPolicy, type TraceRule, type TraceSink, type TraceSinkAsync, type WhenAstV1, createPolicyEngine, formatTrace, validateContext };
|
|
464
|
+
export { type BundleMeta, type ContextPolicy, DEFAULT_CONTEXT_POLICY, type Decision, type DecisionTrace, type DecisionTraceCompact, type DecisionTraceFull, type DecisionTraceHook, type DecisionWithOptionalTrace, type DecisionWithTrace, type Effect, GovplaneError, HttpError, type PolicyDefault, type PolicyEngine, type PolicyEngineEvaluateInput, type RefreshResult, type RuntimeBundleV1, type RuntimeCache, RuntimeClient, type RuntimeClientConfig, type RuntimeClientOptions, type RuntimePolicy, type RuntimeRule, type RuntimeStatus, type StructuredTraceEvent, type Target, type TraceDiscardReason, type TraceLevel, type TraceMode, type TraceOptions, type TraceQueueDropPolicy, type TraceRule, type TraceSink, type TraceSinkAsync, type WhenAstV1, createPolicyEngine, formatTrace, validateContext };
|