@peac/disc 0.12.14 → 0.13.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/dist/index.cjs +16 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -127,6 +127,21 @@ var init_parser = __esm({
|
|
|
127
127
|
|
|
128
128
|
// src/index.ts
|
|
129
129
|
init_parser();
|
|
130
|
+
var __peacDiscDeprecationEmitted = false;
|
|
131
|
+
function __emitPeacDiscDeprecation() {
|
|
132
|
+
if (__peacDiscDeprecationEmitted) return;
|
|
133
|
+
__peacDiscDeprecationEmitted = true;
|
|
134
|
+
if (typeof process !== "undefined" && typeof process.emitWarning === "function") {
|
|
135
|
+
process.emitWarning(
|
|
136
|
+
"@peac/disc is deprecated. Use loadPolicyDocument from @peac/policy-kit. See https://peacprotocol.org/docs/migration for migration steps.",
|
|
137
|
+
{ type: "DeprecationWarning", code: "PEAC_DISC_DEPRECATED" }
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
__emitPeacDiscDeprecation();
|
|
142
|
+
function __resetDiscDeprecationWarningForTests() {
|
|
143
|
+
__peacDiscDeprecationEmitted = false;
|
|
144
|
+
}
|
|
130
145
|
var MAX_BYTES = 262144;
|
|
131
146
|
var WELL_KNOWN_PATH = "/.well-known/peac.txt";
|
|
132
147
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
@@ -191,6 +206,7 @@ async function discover(origin, options = {}) {
|
|
|
191
206
|
exports.DEFAULT_TIMEOUT_MS = DEFAULT_TIMEOUT_MS;
|
|
192
207
|
exports.MAX_BYTES = MAX_BYTES;
|
|
193
208
|
exports.WELL_KNOWN_PATH = WELL_KNOWN_PATH;
|
|
209
|
+
exports.__resetDiscDeprecationWarningForTests = __resetDiscDeprecationWarningForTests;
|
|
194
210
|
exports.__resetLegacyWarningForTests = __resetLegacyWarningForTests;
|
|
195
211
|
exports.discover = discover;
|
|
196
212
|
exports.emit = emit;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parser.ts","../src/index.ts"],"names":["parsePolicyDocument","PolicyValidationError","PolicyLoadError","serializePolicyYaml","parse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @peac/disc/parser - thin peac.txt policy-document loader/validator.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md.\n * Full parsing is delegated to `@peac/policy-kit.parsePolicyDocument`;\n * this module only provides:\n *\n * - format detection (YAML vs JSON) per PEAC-TXT.md §5.1\n * - a tolerant `parse()` wrapper that returns a structured `ParseResult`\n * (rather than throwing)\n * - structured warnings for legacy key-discovery lines (`verify`,\n * `public_keys`, `jwks`) that appeared in pre-v0.12.14 peac.txt\n * examples. Those lines are NEVER honored here: key discovery flows\n * through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md).\n * - a tiny `emit()` helper that serializes a `PolicyDocument` via\n * `@peac/policy-kit.serializePolicyYaml`\n *\n * @see docs/specs/PEAC-TXT.md\n * @see docs/specs/PEAC-ISSUER.md\n */\n\nimport {\n PolicyLoadError,\n PolicyValidationError,\n parsePolicyDocument,\n serializePolicyYaml,\n type PolicyDocument,\n} from '@peac/policy-kit';\nimport type { ParseResult } from './types.js';\n\nconst LEGACY_KEY_LINE = /^\\s*(verify|public_keys|jwks)\\s*:/m;\n/** Strips the whole line (including the trailing newline) when matched. */\nconst LEGACY_KEY_FULL_LINE_GLOBAL = /^\\s*(verify|public_keys|jwks)\\s*:.*\\r?\\n?/gm;\n\nlet legacyWarningFired = false;\n\nfunction fireLegacyWarning(field: string): void {\n if (legacyWarningFired) return;\n legacyWarningFired = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n `peac.txt legacy key-discovery field \"${field}\" is deprecated and ignored. ` +\n `peac.txt is a policy-document surface (docs/specs/PEAC-TXT.md). ` +\n `Key resolution uses iss -> /.well-known/peac-issuer.json -> jwks_uri -> JWKS.`,\n { code: 'PEAC_LEGACY_PEAC_TXT_KEY_FIELD', type: 'DeprecationWarning' }\n );\n }\n}\n\n/**\n * Reset the one-shot legacy-warning flag. Exposed for tests that need to\n * observe the warning more than once per process.\n */\nexport function __resetLegacyWarningForTests(): void {\n legacyWarningFired = false;\n}\n\nfunction collectLegacyWarnings(text: string): { warnings: string[]; firstField: string | null } {\n const warnings: string[] = [];\n let firstField: string | null = null;\n const lines = text.split(/\\r?\\n/);\n lines.forEach((line, idx) => {\n const match = line.match(/^\\s*(verify|public_keys|jwks)\\s*:/);\n if (match) {\n if (firstField === null) firstField = match[1];\n warnings.push(\n `Line ${idx + 1}: legacy key-discovery field \"${match[1]}\" ignored ` +\n `(peac.txt is policy-only; use peac-issuer.json for keys)`\n );\n }\n });\n return { warnings, firstField };\n}\n\n/**\n * Parse a peac.txt policy document. Accepts YAML or JSON per\n * `docs/specs/PEAC-TXT.md` §5.1. On success, `data` is the validated\n * `peac-policy/0.1` `PolicyDocument`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated via a two-pass strategy: first the raw bytes are handed to\n * `parsePolicyDocument`; if validation fails AND top-level legacy lines\n * are present, the legacy lines are stripped and parsing is retried\n * once. Detected legacy lines are listed in `warnings` and surface a\n * structured `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` `DeprecationWarning` once\n * per process. They never populate the parsed result. This preserves\n * the original bytes when a policy document happens to mention those\n * tokens inside comments, block scalars, or rule text.\n */\nexport function parse(text: string): ParseResult {\n const warnings: string[] = [];\n\n if (text.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document. Expected peac-policy/0.1 YAML or JSON.'],\n };\n }\n\n const hasLegacyLines = LEGACY_KEY_LINE.test(text);\n\n // First pass: try the raw bytes. If they parse cleanly, legacy-looking\n // substrings inside block scalars / comments / rule text are not\n // mutated.\n try {\n const data = parsePolicyDocument(text);\n if (hasLegacyLines) {\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n }\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (firstErr) {\n if (!hasLegacyLines) {\n return failure(firstErr, warnings);\n }\n // Second pass: strip top-level legacy key-discovery lines and retry.\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n\n const stripped = text.replace(LEGACY_KEY_FULL_LINE_GLOBAL, '');\n if (stripped.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document after stripping legacy key-discovery lines.'],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n try {\n const data = parsePolicyDocument(stripped);\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (retryErr) {\n return failure(retryErr, warnings);\n }\n }\n}\n\nfunction failure(err: unknown, warnings: string[]): ParseResult {\n if (err instanceof PolicyValidationError || err instanceof PolicyLoadError) {\n return {\n valid: false,\n errors: [err.message],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n return {\n valid: false,\n errors: [err instanceof Error ? err.message : String(err)],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n\n/**\n * Serialize a `peac-policy/0.1` `PolicyDocument` as YAML suitable for\n * serving at `/.well-known/peac.txt`. Delegates to\n * `@peac/policy-kit.serializePolicyYaml`.\n */\nexport function emit(doc: PolicyDocument): string {\n return serializePolicyYaml(doc);\n}\n\n/**\n * Convenience predicate: returns `true` iff `text` parses as a valid\n * `peac-policy/0.1` document.\n */\nexport function validate(text: string): boolean {\n return parse(text).valid;\n}\n","/**\n * @peac/disc - thin peac.txt policy-document loader/validator and remote fetcher.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md. Full\n * parsing is delegated to `@peac/policy-kit.parsePolicyDocument`; this\n * package provides a tolerant `parse()` wrapper, a `discover()` remote\n * fetcher, and structured warnings for legacy key-discovery lines that\n * appeared in older peac.txt examples.\n *\n * `peac.txt` is NOT a key discovery surface. Cryptographic key resolution\n * flows through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md). Callers that need key material MUST use\n * `parseIssuerConfig` / `fetchIssuerConfig` from `@peac/protocol`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated on parse: they are stripped before validation, surfaced on\n * `ParseResult.warnings`, and fire a structured `process.emitWarning`\n * with code `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` once per process.\n */\n\nexport { parse, emit, validate, __resetLegacyWarningForTests } from './parser.js';\nexport type { ParseResult, ValidationOptions, PolicyDocument } from './types.js';\n\n/**\n * @deprecated Retained for one minor to keep existing import paths\n * compiling. peac.txt policy documents now resolve to a `PolicyDocument`\n * (re-exported from `@peac/policy-kit`). Removal target: next cleanup\n * release.\n */\nexport type { PeacDiscovery, PublicKeyInfo } from './types.js';\n\nexport const MAX_BYTES = 262144; // 256 KiB, per docs/specs/PEAC-TXT.md §6.1\nexport const WELL_KNOWN_PATH = '/.well-known/peac.txt';\nexport const DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_USER_AGENT = 'peac-disc';\n\n/**\n * Minimal fetch signature accepted by `discover`. `undici` / `node-fetch` /\n * browser / test-double implementations all satisfy this.\n */\nexport type DiscoverFetch = (\n input: string,\n init?: {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n redirect?: 'follow' | 'error' | 'manual';\n }\n) => Promise<{\n ok: boolean;\n status: number;\n statusText: string;\n text(): Promise<string>;\n}>;\n\nexport interface DiscoverOptions {\n /**\n * HTTP fetch implementation. Defaults to the ambient `fetch` global.\n * Supply `undici.fetch`, a test double, or a policy-wrapping client as\n * needed.\n */\n fetchImpl?: DiscoverFetch;\n /**\n * User-agent string. Precedence (highest first): this option, the\n * `PEAC_USER_AGENT` environment variable, then `peac-disc`.\n */\n userAgent?: string;\n /** Caller-supplied abort signal. */\n signal?: AbortSignal;\n /**\n * Millisecond timeout. Ignored when `signal` is supplied (the caller\n * owns cancellation). Defaults to 5_000 when neither is provided.\n */\n timeoutMs?: number;\n /** Override the 256 KiB body cap from docs/specs/PEAC-TXT.md §6.1. */\n maxBytes?: number;\n /**\n * Redirect policy. Defaults to `error` to avoid cross-origin surprise\n * on a well-known discovery endpoint; set to `follow` explicitly if the\n * deployment relies on server-side redirects.\n */\n redirect?: 'follow' | 'error' | 'manual';\n}\n\n/**\n * Fetch and parse a remote peac.txt policy document. On success returns a\n * `ParseResult` whose `data` is the validated `peac-policy/0.1`\n * `PolicyDocument`. Legacy key-discovery lines in the fetched bytes are\n * surfaced as warnings but never populate `data`.\n */\nexport async function discover(\n origin: string,\n options: DiscoverOptions = {}\n): Promise<import('./types.js').ParseResult> {\n const fetchImpl = (options.fetchImpl ?? (globalThis as { fetch?: DiscoverFetch }).fetch) as\n | DiscoverFetch\n | undefined;\n if (typeof fetchImpl !== 'function') {\n return {\n valid: false,\n errors: [\n 'Discovery failed: no fetch implementation available (supply options.fetchImpl or provide a global fetch)',\n ],\n };\n }\n\n const envUa =\n typeof process !== 'undefined' && typeof process.env === 'object'\n ? process.env.PEAC_USER_AGENT\n : undefined;\n const userAgent = options.userAgent ?? envUa ?? DEFAULT_USER_AGENT;\n const maxBytes = options.maxBytes ?? MAX_BYTES;\n const redirect = options.redirect ?? 'error';\n\n // If the caller did not supply an AbortSignal, install a local one driven by timeoutMs.\n let localController: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let signal = options.signal;\n if (!signal) {\n localController = new AbortController();\n signal = localController.signal;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (timeoutMs > 0 && Number.isFinite(timeoutMs)) {\n timer = setTimeout(() => localController?.abort(), timeoutMs);\n }\n }\n\n try {\n const url = new URL(WELL_KNOWN_PATH, origin);\n const response = await fetchImpl(url.toString(), {\n headers: { 'User-Agent': userAgent },\n signal,\n redirect,\n });\n\n if (!response.ok) {\n return {\n valid: false,\n errors: [`HTTP ${response.status}: ${response.statusText}`],\n };\n }\n\n const content = await response.text();\n if (content.length > maxBytes) {\n return {\n valid: false,\n errors: [`peac.txt exceeds ${maxBytes} bytes (got ${content.length})`],\n };\n }\n const { parse } = await import('./parser.js');\n return parse(content);\n } catch (error) {\n return {\n valid: false,\n errors: [`Discovery failed: ${error instanceof Error ? error.message : String(error)}`],\n };\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/parser.ts","../src/index.ts"],"names":["parsePolicyDocument","PolicyValidationError","PolicyLoadError","serializePolicyYaml","parse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @peac/disc/parser - thin peac.txt policy-document loader/validator.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md.\n * Full parsing is delegated to `@peac/policy-kit.parsePolicyDocument`;\n * this module only provides:\n *\n * - format detection (YAML vs JSON) per PEAC-TXT.md §5.1\n * - a tolerant `parse()` wrapper that returns a structured `ParseResult`\n * (rather than throwing)\n * - structured warnings for legacy key-discovery lines (`verify`,\n * `public_keys`, `jwks`) that appeared in pre-v0.12.14 peac.txt\n * examples. Those lines are NEVER honored here: key discovery flows\n * through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md).\n * - a tiny `emit()` helper that serializes a `PolicyDocument` via\n * `@peac/policy-kit.serializePolicyYaml`\n *\n * @see docs/specs/PEAC-TXT.md\n * @see docs/specs/PEAC-ISSUER.md\n */\n\nimport {\n PolicyLoadError,\n PolicyValidationError,\n parsePolicyDocument,\n serializePolicyYaml,\n type PolicyDocument,\n} from '@peac/policy-kit';\nimport type { ParseResult } from './types.js';\n\nconst LEGACY_KEY_LINE = /^\\s*(verify|public_keys|jwks)\\s*:/m;\n/** Strips the whole line (including the trailing newline) when matched. */\nconst LEGACY_KEY_FULL_LINE_GLOBAL = /^\\s*(verify|public_keys|jwks)\\s*:.*\\r?\\n?/gm;\n\nlet legacyWarningFired = false;\n\nfunction fireLegacyWarning(field: string): void {\n if (legacyWarningFired) return;\n legacyWarningFired = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n `peac.txt legacy key-discovery field \"${field}\" is deprecated and ignored. ` +\n `peac.txt is a policy-document surface (docs/specs/PEAC-TXT.md). ` +\n `Key resolution uses iss -> /.well-known/peac-issuer.json -> jwks_uri -> JWKS.`,\n { code: 'PEAC_LEGACY_PEAC_TXT_KEY_FIELD', type: 'DeprecationWarning' }\n );\n }\n}\n\n/**\n * Reset the one-shot legacy-warning flag. Exposed for tests that need to\n * observe the warning more than once per process.\n */\nexport function __resetLegacyWarningForTests(): void {\n legacyWarningFired = false;\n}\n\nfunction collectLegacyWarnings(text: string): { warnings: string[]; firstField: string | null } {\n const warnings: string[] = [];\n let firstField: string | null = null;\n const lines = text.split(/\\r?\\n/);\n lines.forEach((line, idx) => {\n const match = line.match(/^\\s*(verify|public_keys|jwks)\\s*:/);\n if (match) {\n if (firstField === null) firstField = match[1];\n warnings.push(\n `Line ${idx + 1}: legacy key-discovery field \"${match[1]}\" ignored ` +\n `(peac.txt is policy-only; use peac-issuer.json for keys)`\n );\n }\n });\n return { warnings, firstField };\n}\n\n/**\n * Parse a peac.txt policy document. Accepts YAML or JSON per\n * `docs/specs/PEAC-TXT.md` §5.1. On success, `data` is the validated\n * `peac-policy/0.1` `PolicyDocument`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated via a two-pass strategy: first the raw bytes are handed to\n * `parsePolicyDocument`; if validation fails AND top-level legacy lines\n * are present, the legacy lines are stripped and parsing is retried\n * once. Detected legacy lines are listed in `warnings` and surface a\n * structured `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` `DeprecationWarning` once\n * per process. They never populate the parsed result. This preserves\n * the original bytes when a policy document happens to mention those\n * tokens inside comments, block scalars, or rule text.\n */\nexport function parse(text: string): ParseResult {\n const warnings: string[] = [];\n\n if (text.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document. Expected peac-policy/0.1 YAML or JSON.'],\n };\n }\n\n const hasLegacyLines = LEGACY_KEY_LINE.test(text);\n\n // First pass: try the raw bytes. If they parse cleanly, legacy-looking\n // substrings inside block scalars / comments / rule text are not\n // mutated.\n try {\n const data = parsePolicyDocument(text);\n if (hasLegacyLines) {\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n }\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (firstErr) {\n if (!hasLegacyLines) {\n return failure(firstErr, warnings);\n }\n // Second pass: strip top-level legacy key-discovery lines and retry.\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n\n const stripped = text.replace(LEGACY_KEY_FULL_LINE_GLOBAL, '');\n if (stripped.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document after stripping legacy key-discovery lines.'],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n try {\n const data = parsePolicyDocument(stripped);\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (retryErr) {\n return failure(retryErr, warnings);\n }\n }\n}\n\nfunction failure(err: unknown, warnings: string[]): ParseResult {\n if (err instanceof PolicyValidationError || err instanceof PolicyLoadError) {\n return {\n valid: false,\n errors: [err.message],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n return {\n valid: false,\n errors: [err instanceof Error ? err.message : String(err)],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n\n/**\n * Serialize a `peac-policy/0.1` `PolicyDocument` as YAML suitable for\n * serving at `/.well-known/peac.txt`. Delegates to\n * `@peac/policy-kit.serializePolicyYaml`.\n */\nexport function emit(doc: PolicyDocument): string {\n return serializePolicyYaml(doc);\n}\n\n/**\n * Convenience predicate: returns `true` iff `text` parses as a valid\n * `peac-policy/0.1` document.\n */\nexport function validate(text: string): boolean {\n return parse(text).valid;\n}\n","/**\n * @peac/disc - DEPRECATED. Thin peac.txt policy-document loader/validator and\n * remote fetcher. Retained as a published deprecated compatibility package\n * so that existing workspace and external consumers continue to resolve.\n *\n * @deprecated Prefer {@link \"@peac/policy-kit\"} for policy-document parsing\n * and validation (`parsePolicyDocument`, `loadPolicyDocument`,\n * `validatePolicy`, `serializePolicyYaml`). Remote discovery behavior in\n * `discover()` (SSRF-aware fetch with a byte cap, timeout policy, and\n * redirect policy) has no direct equivalent in `@peac/policy-kit` and\n * remains compatibility-only here until an equivalent replacement ships.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md. Full\n * parsing is delegated to `@peac/policy-kit.parsePolicyDocument`; this\n * package provides a tolerant `parse()` wrapper, a `discover()` remote\n * fetcher, and structured warnings for legacy key-discovery lines that\n * appeared in older peac.txt examples.\n *\n * `peac.txt` is NOT a key discovery surface. Cryptographic key resolution\n * flows through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md). Callers that need key material MUST use\n * `parseIssuerConfig` / `fetchIssuerConfig` from `@peac/protocol`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated on parse: they are stripped before validation, surfaced on\n * `ParseResult.warnings`, and fire a structured `process.emitWarning`\n * with code `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` once per process.\n */\n\n// One-shot structured deprecation warning on module load. Use\n// process.emitWarning with a stable code plus DeprecationWarning type so\n// operators can filter on NODE_OPTIONS=--no-deprecation if needed. Single\n// shot per process to avoid log spam in hot paths.\nlet __peacDiscDeprecationEmitted = false;\nfunction __emitPeacDiscDeprecation(): void {\n if (__peacDiscDeprecationEmitted) return;\n __peacDiscDeprecationEmitted = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n '@peac/disc is deprecated. Use loadPolicyDocument from @peac/policy-kit. ' +\n 'See https://peacprotocol.org/docs/migration for migration steps.',\n { type: 'DeprecationWarning', code: 'PEAC_DISC_DEPRECATED' }\n );\n }\n}\n__emitPeacDiscDeprecation();\n\n/** @internal test-only hook to reset the one-shot deprecation flag. */\nexport function __resetDiscDeprecationWarningForTests(): void {\n __peacDiscDeprecationEmitted = false;\n}\n\nexport { parse, emit, validate, __resetLegacyWarningForTests } from './parser.js';\nexport type { ParseResult, ValidationOptions, PolicyDocument } from './types.js';\n\n/**\n * @deprecated Retained for one minor to keep existing import paths\n * compiling. peac.txt policy documents now resolve to a `PolicyDocument`\n * (re-exported from `@peac/policy-kit`).\n */\nexport type { PeacDiscovery, PublicKeyInfo } from './types.js';\n\nexport const MAX_BYTES = 262144; // 256 KiB, per docs/specs/PEAC-TXT.md §6.1\nexport const WELL_KNOWN_PATH = '/.well-known/peac.txt';\nexport const DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_USER_AGENT = 'peac-disc';\n\n/**\n * Minimal fetch signature accepted by `discover`. `undici` / `node-fetch` /\n * browser / test-double implementations all satisfy this.\n */\nexport type DiscoverFetch = (\n input: string,\n init?: {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n redirect?: 'follow' | 'error' | 'manual';\n }\n) => Promise<{\n ok: boolean;\n status: number;\n statusText: string;\n text(): Promise<string>;\n}>;\n\nexport interface DiscoverOptions {\n /**\n * HTTP fetch implementation. Defaults to the ambient `fetch` global.\n * Supply `undici.fetch`, a test double, or a policy-wrapping client as\n * needed.\n */\n fetchImpl?: DiscoverFetch;\n /**\n * User-agent string. Precedence (highest first): this option, the\n * `PEAC_USER_AGENT` environment variable, then `peac-disc`.\n */\n userAgent?: string;\n /** Caller-supplied abort signal. */\n signal?: AbortSignal;\n /**\n * Millisecond timeout. Ignored when `signal` is supplied (the caller\n * owns cancellation). Defaults to 5_000 when neither is provided.\n */\n timeoutMs?: number;\n /** Override the 256 KiB body cap from docs/specs/PEAC-TXT.md §6.1. */\n maxBytes?: number;\n /**\n * Redirect policy. Defaults to `error` to avoid cross-origin surprise\n * on a well-known discovery endpoint; set to `follow` explicitly if the\n * deployment relies on server-side redirects.\n */\n redirect?: 'follow' | 'error' | 'manual';\n}\n\n/**\n * Fetch and parse a remote peac.txt policy document. On success returns a\n * `ParseResult` whose `data` is the validated `peac-policy/0.1`\n * `PolicyDocument`. Legacy key-discovery lines in the fetched bytes are\n * surfaced as warnings but never populate `data`.\n */\nexport async function discover(\n origin: string,\n options: DiscoverOptions = {}\n): Promise<import('./types.js').ParseResult> {\n const fetchImpl = (options.fetchImpl ?? (globalThis as { fetch?: DiscoverFetch }).fetch) as\n | DiscoverFetch\n | undefined;\n if (typeof fetchImpl !== 'function') {\n return {\n valid: false,\n errors: [\n 'Discovery failed: no fetch implementation available (supply options.fetchImpl or provide a global fetch)',\n ],\n };\n }\n\n const envUa =\n typeof process !== 'undefined' && typeof process.env === 'object'\n ? process.env.PEAC_USER_AGENT\n : undefined;\n const userAgent = options.userAgent ?? envUa ?? DEFAULT_USER_AGENT;\n const maxBytes = options.maxBytes ?? MAX_BYTES;\n const redirect = options.redirect ?? 'error';\n\n // If the caller did not supply an AbortSignal, install a local one driven by timeoutMs.\n let localController: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let signal = options.signal;\n if (!signal) {\n localController = new AbortController();\n signal = localController.signal;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (timeoutMs > 0 && Number.isFinite(timeoutMs)) {\n timer = setTimeout(() => localController?.abort(), timeoutMs);\n }\n }\n\n try {\n const url = new URL(WELL_KNOWN_PATH, origin);\n const response = await fetchImpl(url.toString(), {\n headers: { 'User-Agent': userAgent },\n signal,\n redirect,\n });\n\n if (!response.ok) {\n return {\n valid: false,\n errors: [`HTTP ${response.status}: ${response.statusText}`],\n };\n }\n\n const content = await response.text();\n if (content.length > maxBytes) {\n return {\n valid: false,\n errors: [`peac.txt exceeds ${maxBytes} bytes (got ${content.length})`],\n };\n }\n const { parse } = await import('./parser.js');\n return parse(content);\n } catch (error) {\n return {\n valid: false,\n errors: [`Discovery failed: ${error instanceof Error ? error.message : String(error)}`],\n };\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @peac/disc -
|
|
2
|
+
* @peac/disc - DEPRECATED. Thin peac.txt policy-document loader/validator and
|
|
3
|
+
* remote fetcher. Retained as a published deprecated compatibility package
|
|
4
|
+
* so that existing workspace and external consumers continue to resolve.
|
|
5
|
+
*
|
|
6
|
+
* @deprecated Prefer {@link "@peac/policy-kit"} for policy-document parsing
|
|
7
|
+
* and validation (`parsePolicyDocument`, `loadPolicyDocument`,
|
|
8
|
+
* `validatePolicy`, `serializePolicyYaml`). Remote discovery behavior in
|
|
9
|
+
* `discover()` (SSRF-aware fetch with a byte cap, timeout policy, and
|
|
10
|
+
* redirect policy) has no direct equivalent in `@peac/policy-kit` and
|
|
11
|
+
* remains compatibility-only here until an equivalent replacement ships.
|
|
3
12
|
*
|
|
4
13
|
* peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md. Full
|
|
5
14
|
* parsing is delegated to `@peac/policy-kit.parsePolicyDocument`; this
|
|
@@ -17,13 +26,14 @@
|
|
|
17
26
|
* `ParseResult.warnings`, and fire a structured `process.emitWarning`
|
|
18
27
|
* with code `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` once per process.
|
|
19
28
|
*/
|
|
29
|
+
/** @internal test-only hook to reset the one-shot deprecation flag. */
|
|
30
|
+
export declare function __resetDiscDeprecationWarningForTests(): void;
|
|
20
31
|
export { parse, emit, validate, __resetLegacyWarningForTests } from './parser.js';
|
|
21
32
|
export type { ParseResult, ValidationOptions, PolicyDocument } from './types.js';
|
|
22
33
|
/**
|
|
23
34
|
* @deprecated Retained for one minor to keep existing import paths
|
|
24
35
|
* compiling. peac.txt policy documents now resolve to a `PolicyDocument`
|
|
25
|
-
* (re-exported from `@peac/policy-kit`).
|
|
26
|
-
* release.
|
|
36
|
+
* (re-exported from `@peac/policy-kit`).
|
|
27
37
|
*/
|
|
28
38
|
export type { PeacDiscovery, PublicKeyInfo } from './types.js';
|
|
29
39
|
export declare const MAX_BYTES = 262144;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAoBH,uEAAuE;AACvE,wBAAgB,qCAAqC,IAAI,IAAI,CAE5D;AAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAClF,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjF;;;;GAIG;AACH,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/D,eAAO,MAAM,SAAS,SAAS,CAAC;AAChC,eAAO,MAAM,eAAe,0BAA0B,CAAC;AACvD,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAGvC;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IACL,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;CAC1C,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,OAAO,YAAY,EAAE,WAAW,CAAC,CAkE3C"}
|
package/dist/index.js
CHANGED
|
@@ -125,6 +125,21 @@ var init_parser = __esm({
|
|
|
125
125
|
|
|
126
126
|
// src/index.ts
|
|
127
127
|
init_parser();
|
|
128
|
+
var __peacDiscDeprecationEmitted = false;
|
|
129
|
+
function __emitPeacDiscDeprecation() {
|
|
130
|
+
if (__peacDiscDeprecationEmitted) return;
|
|
131
|
+
__peacDiscDeprecationEmitted = true;
|
|
132
|
+
if (typeof process !== "undefined" && typeof process.emitWarning === "function") {
|
|
133
|
+
process.emitWarning(
|
|
134
|
+
"@peac/disc is deprecated. Use loadPolicyDocument from @peac/policy-kit. See https://peacprotocol.org/docs/migration for migration steps.",
|
|
135
|
+
{ type: "DeprecationWarning", code: "PEAC_DISC_DEPRECATED" }
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
__emitPeacDiscDeprecation();
|
|
140
|
+
function __resetDiscDeprecationWarningForTests() {
|
|
141
|
+
__peacDiscDeprecationEmitted = false;
|
|
142
|
+
}
|
|
128
143
|
var MAX_BYTES = 262144;
|
|
129
144
|
var WELL_KNOWN_PATH = "/.well-known/peac.txt";
|
|
130
145
|
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
@@ -186,6 +201,6 @@ async function discover(origin, options = {}) {
|
|
|
186
201
|
}
|
|
187
202
|
}
|
|
188
203
|
|
|
189
|
-
export { DEFAULT_TIMEOUT_MS, MAX_BYTES, WELL_KNOWN_PATH, __resetLegacyWarningForTests, discover, emit, parse, validate };
|
|
204
|
+
export { DEFAULT_TIMEOUT_MS, MAX_BYTES, WELL_KNOWN_PATH, __resetDiscDeprecationWarningForTests, __resetLegacyWarningForTests, discover, emit, parse, validate };
|
|
190
205
|
//# sourceMappingURL=index.js.map
|
|
191
206
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parser.ts","../src/index.ts"],"names":["parse"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @peac/disc/parser - thin peac.txt policy-document loader/validator.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md.\n * Full parsing is delegated to `@peac/policy-kit.parsePolicyDocument`;\n * this module only provides:\n *\n * - format detection (YAML vs JSON) per PEAC-TXT.md §5.1\n * - a tolerant `parse()` wrapper that returns a structured `ParseResult`\n * (rather than throwing)\n * - structured warnings for legacy key-discovery lines (`verify`,\n * `public_keys`, `jwks`) that appeared in pre-v0.12.14 peac.txt\n * examples. Those lines are NEVER honored here: key discovery flows\n * through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md).\n * - a tiny `emit()` helper that serializes a `PolicyDocument` via\n * `@peac/policy-kit.serializePolicyYaml`\n *\n * @see docs/specs/PEAC-TXT.md\n * @see docs/specs/PEAC-ISSUER.md\n */\n\nimport {\n PolicyLoadError,\n PolicyValidationError,\n parsePolicyDocument,\n serializePolicyYaml,\n type PolicyDocument,\n} from '@peac/policy-kit';\nimport type { ParseResult } from './types.js';\n\nconst LEGACY_KEY_LINE = /^\\s*(verify|public_keys|jwks)\\s*:/m;\n/** Strips the whole line (including the trailing newline) when matched. */\nconst LEGACY_KEY_FULL_LINE_GLOBAL = /^\\s*(verify|public_keys|jwks)\\s*:.*\\r?\\n?/gm;\n\nlet legacyWarningFired = false;\n\nfunction fireLegacyWarning(field: string): void {\n if (legacyWarningFired) return;\n legacyWarningFired = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n `peac.txt legacy key-discovery field \"${field}\" is deprecated and ignored. ` +\n `peac.txt is a policy-document surface (docs/specs/PEAC-TXT.md). ` +\n `Key resolution uses iss -> /.well-known/peac-issuer.json -> jwks_uri -> JWKS.`,\n { code: 'PEAC_LEGACY_PEAC_TXT_KEY_FIELD', type: 'DeprecationWarning' }\n );\n }\n}\n\n/**\n * Reset the one-shot legacy-warning flag. Exposed for tests that need to\n * observe the warning more than once per process.\n */\nexport function __resetLegacyWarningForTests(): void {\n legacyWarningFired = false;\n}\n\nfunction collectLegacyWarnings(text: string): { warnings: string[]; firstField: string | null } {\n const warnings: string[] = [];\n let firstField: string | null = null;\n const lines = text.split(/\\r?\\n/);\n lines.forEach((line, idx) => {\n const match = line.match(/^\\s*(verify|public_keys|jwks)\\s*:/);\n if (match) {\n if (firstField === null) firstField = match[1];\n warnings.push(\n `Line ${idx + 1}: legacy key-discovery field \"${match[1]}\" ignored ` +\n `(peac.txt is policy-only; use peac-issuer.json for keys)`\n );\n }\n });\n return { warnings, firstField };\n}\n\n/**\n * Parse a peac.txt policy document. Accepts YAML or JSON per\n * `docs/specs/PEAC-TXT.md` §5.1. On success, `data` is the validated\n * `peac-policy/0.1` `PolicyDocument`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated via a two-pass strategy: first the raw bytes are handed to\n * `parsePolicyDocument`; if validation fails AND top-level legacy lines\n * are present, the legacy lines are stripped and parsing is retried\n * once. Detected legacy lines are listed in `warnings` and surface a\n * structured `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` `DeprecationWarning` once\n * per process. They never populate the parsed result. This preserves\n * the original bytes when a policy document happens to mention those\n * tokens inside comments, block scalars, or rule text.\n */\nexport function parse(text: string): ParseResult {\n const warnings: string[] = [];\n\n if (text.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document. Expected peac-policy/0.1 YAML or JSON.'],\n };\n }\n\n const hasLegacyLines = LEGACY_KEY_LINE.test(text);\n\n // First pass: try the raw bytes. If they parse cleanly, legacy-looking\n // substrings inside block scalars / comments / rule text are not\n // mutated.\n try {\n const data = parsePolicyDocument(text);\n if (hasLegacyLines) {\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n }\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (firstErr) {\n if (!hasLegacyLines) {\n return failure(firstErr, warnings);\n }\n // Second pass: strip top-level legacy key-discovery lines and retry.\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n\n const stripped = text.replace(LEGACY_KEY_FULL_LINE_GLOBAL, '');\n if (stripped.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document after stripping legacy key-discovery lines.'],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n try {\n const data = parsePolicyDocument(stripped);\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (retryErr) {\n return failure(retryErr, warnings);\n }\n }\n}\n\nfunction failure(err: unknown, warnings: string[]): ParseResult {\n if (err instanceof PolicyValidationError || err instanceof PolicyLoadError) {\n return {\n valid: false,\n errors: [err.message],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n return {\n valid: false,\n errors: [err instanceof Error ? err.message : String(err)],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n\n/**\n * Serialize a `peac-policy/0.1` `PolicyDocument` as YAML suitable for\n * serving at `/.well-known/peac.txt`. Delegates to\n * `@peac/policy-kit.serializePolicyYaml`.\n */\nexport function emit(doc: PolicyDocument): string {\n return serializePolicyYaml(doc);\n}\n\n/**\n * Convenience predicate: returns `true` iff `text` parses as a valid\n * `peac-policy/0.1` document.\n */\nexport function validate(text: string): boolean {\n return parse(text).valid;\n}\n","/**\n * @peac/disc - thin peac.txt policy-document loader/validator and remote fetcher.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md. Full\n * parsing is delegated to `@peac/policy-kit.parsePolicyDocument`; this\n * package provides a tolerant `parse()` wrapper, a `discover()` remote\n * fetcher, and structured warnings for legacy key-discovery lines that\n * appeared in older peac.txt examples.\n *\n * `peac.txt` is NOT a key discovery surface. Cryptographic key resolution\n * flows through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md). Callers that need key material MUST use\n * `parseIssuerConfig` / `fetchIssuerConfig` from `@peac/protocol`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated on parse: they are stripped before validation, surfaced on\n * `ParseResult.warnings`, and fire a structured `process.emitWarning`\n * with code `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` once per process.\n */\n\nexport { parse, emit, validate, __resetLegacyWarningForTests } from './parser.js';\nexport type { ParseResult, ValidationOptions, PolicyDocument } from './types.js';\n\n/**\n * @deprecated Retained for one minor to keep existing import paths\n * compiling. peac.txt policy documents now resolve to a `PolicyDocument`\n * (re-exported from `@peac/policy-kit`). Removal target: next cleanup\n * release.\n */\nexport type { PeacDiscovery, PublicKeyInfo } from './types.js';\n\nexport const MAX_BYTES = 262144; // 256 KiB, per docs/specs/PEAC-TXT.md §6.1\nexport const WELL_KNOWN_PATH = '/.well-known/peac.txt';\nexport const DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_USER_AGENT = 'peac-disc';\n\n/**\n * Minimal fetch signature accepted by `discover`. `undici` / `node-fetch` /\n * browser / test-double implementations all satisfy this.\n */\nexport type DiscoverFetch = (\n input: string,\n init?: {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n redirect?: 'follow' | 'error' | 'manual';\n }\n) => Promise<{\n ok: boolean;\n status: number;\n statusText: string;\n text(): Promise<string>;\n}>;\n\nexport interface DiscoverOptions {\n /**\n * HTTP fetch implementation. Defaults to the ambient `fetch` global.\n * Supply `undici.fetch`, a test double, or a policy-wrapping client as\n * needed.\n */\n fetchImpl?: DiscoverFetch;\n /**\n * User-agent string. Precedence (highest first): this option, the\n * `PEAC_USER_AGENT` environment variable, then `peac-disc`.\n */\n userAgent?: string;\n /** Caller-supplied abort signal. */\n signal?: AbortSignal;\n /**\n * Millisecond timeout. Ignored when `signal` is supplied (the caller\n * owns cancellation). Defaults to 5_000 when neither is provided.\n */\n timeoutMs?: number;\n /** Override the 256 KiB body cap from docs/specs/PEAC-TXT.md §6.1. */\n maxBytes?: number;\n /**\n * Redirect policy. Defaults to `error` to avoid cross-origin surprise\n * on a well-known discovery endpoint; set to `follow` explicitly if the\n * deployment relies on server-side redirects.\n */\n redirect?: 'follow' | 'error' | 'manual';\n}\n\n/**\n * Fetch and parse a remote peac.txt policy document. On success returns a\n * `ParseResult` whose `data` is the validated `peac-policy/0.1`\n * `PolicyDocument`. Legacy key-discovery lines in the fetched bytes are\n * surfaced as warnings but never populate `data`.\n */\nexport async function discover(\n origin: string,\n options: DiscoverOptions = {}\n): Promise<import('./types.js').ParseResult> {\n const fetchImpl = (options.fetchImpl ?? (globalThis as { fetch?: DiscoverFetch }).fetch) as\n | DiscoverFetch\n | undefined;\n if (typeof fetchImpl !== 'function') {\n return {\n valid: false,\n errors: [\n 'Discovery failed: no fetch implementation available (supply options.fetchImpl or provide a global fetch)',\n ],\n };\n }\n\n const envUa =\n typeof process !== 'undefined' && typeof process.env === 'object'\n ? process.env.PEAC_USER_AGENT\n : undefined;\n const userAgent = options.userAgent ?? envUa ?? DEFAULT_USER_AGENT;\n const maxBytes = options.maxBytes ?? MAX_BYTES;\n const redirect = options.redirect ?? 'error';\n\n // If the caller did not supply an AbortSignal, install a local one driven by timeoutMs.\n let localController: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let signal = options.signal;\n if (!signal) {\n localController = new AbortController();\n signal = localController.signal;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (timeoutMs > 0 && Number.isFinite(timeoutMs)) {\n timer = setTimeout(() => localController?.abort(), timeoutMs);\n }\n }\n\n try {\n const url = new URL(WELL_KNOWN_PATH, origin);\n const response = await fetchImpl(url.toString(), {\n headers: { 'User-Agent': userAgent },\n signal,\n redirect,\n });\n\n if (!response.ok) {\n return {\n valid: false,\n errors: [`HTTP ${response.status}: ${response.statusText}`],\n };\n }\n\n const content = await response.text();\n if (content.length > maxBytes) {\n return {\n valid: false,\n errors: [`peac.txt exceeds ${maxBytes} bytes (got ${content.length})`],\n };\n }\n const { parse } = await import('./parser.js');\n return parse(content);\n } catch (error) {\n return {\n valid: false,\n errors: [`Discovery failed: ${error instanceof Error ? error.message : String(error)}`],\n };\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/parser.ts","../src/index.ts"],"names":["parse"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @peac/disc/parser - thin peac.txt policy-document loader/validator.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md.\n * Full parsing is delegated to `@peac/policy-kit.parsePolicyDocument`;\n * this module only provides:\n *\n * - format detection (YAML vs JSON) per PEAC-TXT.md §5.1\n * - a tolerant `parse()` wrapper that returns a structured `ParseResult`\n * (rather than throwing)\n * - structured warnings for legacy key-discovery lines (`verify`,\n * `public_keys`, `jwks`) that appeared in pre-v0.12.14 peac.txt\n * examples. Those lines are NEVER honored here: key discovery flows\n * through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md).\n * - a tiny `emit()` helper that serializes a `PolicyDocument` via\n * `@peac/policy-kit.serializePolicyYaml`\n *\n * @see docs/specs/PEAC-TXT.md\n * @see docs/specs/PEAC-ISSUER.md\n */\n\nimport {\n PolicyLoadError,\n PolicyValidationError,\n parsePolicyDocument,\n serializePolicyYaml,\n type PolicyDocument,\n} from '@peac/policy-kit';\nimport type { ParseResult } from './types.js';\n\nconst LEGACY_KEY_LINE = /^\\s*(verify|public_keys|jwks)\\s*:/m;\n/** Strips the whole line (including the trailing newline) when matched. */\nconst LEGACY_KEY_FULL_LINE_GLOBAL = /^\\s*(verify|public_keys|jwks)\\s*:.*\\r?\\n?/gm;\n\nlet legacyWarningFired = false;\n\nfunction fireLegacyWarning(field: string): void {\n if (legacyWarningFired) return;\n legacyWarningFired = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n `peac.txt legacy key-discovery field \"${field}\" is deprecated and ignored. ` +\n `peac.txt is a policy-document surface (docs/specs/PEAC-TXT.md). ` +\n `Key resolution uses iss -> /.well-known/peac-issuer.json -> jwks_uri -> JWKS.`,\n { code: 'PEAC_LEGACY_PEAC_TXT_KEY_FIELD', type: 'DeprecationWarning' }\n );\n }\n}\n\n/**\n * Reset the one-shot legacy-warning flag. Exposed for tests that need to\n * observe the warning more than once per process.\n */\nexport function __resetLegacyWarningForTests(): void {\n legacyWarningFired = false;\n}\n\nfunction collectLegacyWarnings(text: string): { warnings: string[]; firstField: string | null } {\n const warnings: string[] = [];\n let firstField: string | null = null;\n const lines = text.split(/\\r?\\n/);\n lines.forEach((line, idx) => {\n const match = line.match(/^\\s*(verify|public_keys|jwks)\\s*:/);\n if (match) {\n if (firstField === null) firstField = match[1];\n warnings.push(\n `Line ${idx + 1}: legacy key-discovery field \"${match[1]}\" ignored ` +\n `(peac.txt is policy-only; use peac-issuer.json for keys)`\n );\n }\n });\n return { warnings, firstField };\n}\n\n/**\n * Parse a peac.txt policy document. Accepts YAML or JSON per\n * `docs/specs/PEAC-TXT.md` §5.1. On success, `data` is the validated\n * `peac-policy/0.1` `PolicyDocument`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated via a two-pass strategy: first the raw bytes are handed to\n * `parsePolicyDocument`; if validation fails AND top-level legacy lines\n * are present, the legacy lines are stripped and parsing is retried\n * once. Detected legacy lines are listed in `warnings` and surface a\n * structured `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` `DeprecationWarning` once\n * per process. They never populate the parsed result. This preserves\n * the original bytes when a policy document happens to mention those\n * tokens inside comments, block scalars, or rule text.\n */\nexport function parse(text: string): ParseResult {\n const warnings: string[] = [];\n\n if (text.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document. Expected peac-policy/0.1 YAML or JSON.'],\n };\n }\n\n const hasLegacyLines = LEGACY_KEY_LINE.test(text);\n\n // First pass: try the raw bytes. If they parse cleanly, legacy-looking\n // substrings inside block scalars / comments / rule text are not\n // mutated.\n try {\n const data = parsePolicyDocument(text);\n if (hasLegacyLines) {\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n }\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (firstErr) {\n if (!hasLegacyLines) {\n return failure(firstErr, warnings);\n }\n // Second pass: strip top-level legacy key-discovery lines and retry.\n const legacy = collectLegacyWarnings(text);\n warnings.push(...legacy.warnings);\n if (legacy.firstField) fireLegacyWarning(legacy.firstField);\n\n const stripped = text.replace(LEGACY_KEY_FULL_LINE_GLOBAL, '');\n if (stripped.trim().length === 0) {\n return {\n valid: false,\n errors: ['Empty policy document after stripping legacy key-discovery lines.'],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n try {\n const data = parsePolicyDocument(stripped);\n return {\n valid: true,\n data,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n } catch (retryErr) {\n return failure(retryErr, warnings);\n }\n }\n}\n\nfunction failure(err: unknown, warnings: string[]): ParseResult {\n if (err instanceof PolicyValidationError || err instanceof PolicyLoadError) {\n return {\n valid: false,\n errors: [err.message],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n return {\n valid: false,\n errors: [err instanceof Error ? err.message : String(err)],\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n\n/**\n * Serialize a `peac-policy/0.1` `PolicyDocument` as YAML suitable for\n * serving at `/.well-known/peac.txt`. Delegates to\n * `@peac/policy-kit.serializePolicyYaml`.\n */\nexport function emit(doc: PolicyDocument): string {\n return serializePolicyYaml(doc);\n}\n\n/**\n * Convenience predicate: returns `true` iff `text` parses as a valid\n * `peac-policy/0.1` document.\n */\nexport function validate(text: string): boolean {\n return parse(text).valid;\n}\n","/**\n * @peac/disc - DEPRECATED. Thin peac.txt policy-document loader/validator and\n * remote fetcher. Retained as a published deprecated compatibility package\n * so that existing workspace and external consumers continue to resolve.\n *\n * @deprecated Prefer {@link \"@peac/policy-kit\"} for policy-document parsing\n * and validation (`parsePolicyDocument`, `loadPolicyDocument`,\n * `validatePolicy`, `serializePolicyYaml`). Remote discovery behavior in\n * `discover()` (SSRF-aware fetch with a byte cap, timeout policy, and\n * redirect policy) has no direct equivalent in `@peac/policy-kit` and\n * remains compatibility-only here until an equivalent replacement ships.\n *\n * peac.txt is a POLICY DOCUMENT surface per docs/specs/PEAC-TXT.md. Full\n * parsing is delegated to `@peac/policy-kit.parsePolicyDocument`; this\n * package provides a tolerant `parse()` wrapper, a `discover()` remote\n * fetcher, and structured warnings for legacy key-discovery lines that\n * appeared in older peac.txt examples.\n *\n * `peac.txt` is NOT a key discovery surface. Cryptographic key resolution\n * flows through `iss` -> /.well-known/peac-issuer.json -> `jwks_uri` -> JWKS\n * (docs/specs/PEAC-ISSUER.md). Callers that need key material MUST use\n * `parseIssuerConfig` / `fetchIssuerConfig` from `@peac/protocol`.\n *\n * Legacy key-discovery lines (`verify:`, `public_keys:`, `jwks:`) are\n * tolerated on parse: they are stripped before validation, surfaced on\n * `ParseResult.warnings`, and fire a structured `process.emitWarning`\n * with code `PEAC_LEGACY_PEAC_TXT_KEY_FIELD` once per process.\n */\n\n// One-shot structured deprecation warning on module load. Use\n// process.emitWarning with a stable code plus DeprecationWarning type so\n// operators can filter on NODE_OPTIONS=--no-deprecation if needed. Single\n// shot per process to avoid log spam in hot paths.\nlet __peacDiscDeprecationEmitted = false;\nfunction __emitPeacDiscDeprecation(): void {\n if (__peacDiscDeprecationEmitted) return;\n __peacDiscDeprecationEmitted = true;\n if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {\n process.emitWarning(\n '@peac/disc is deprecated. Use loadPolicyDocument from @peac/policy-kit. ' +\n 'See https://peacprotocol.org/docs/migration for migration steps.',\n { type: 'DeprecationWarning', code: 'PEAC_DISC_DEPRECATED' }\n );\n }\n}\n__emitPeacDiscDeprecation();\n\n/** @internal test-only hook to reset the one-shot deprecation flag. */\nexport function __resetDiscDeprecationWarningForTests(): void {\n __peacDiscDeprecationEmitted = false;\n}\n\nexport { parse, emit, validate, __resetLegacyWarningForTests } from './parser.js';\nexport type { ParseResult, ValidationOptions, PolicyDocument } from './types.js';\n\n/**\n * @deprecated Retained for one minor to keep existing import paths\n * compiling. peac.txt policy documents now resolve to a `PolicyDocument`\n * (re-exported from `@peac/policy-kit`).\n */\nexport type { PeacDiscovery, PublicKeyInfo } from './types.js';\n\nexport const MAX_BYTES = 262144; // 256 KiB, per docs/specs/PEAC-TXT.md §6.1\nexport const WELL_KNOWN_PATH = '/.well-known/peac.txt';\nexport const DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_USER_AGENT = 'peac-disc';\n\n/**\n * Minimal fetch signature accepted by `discover`. `undici` / `node-fetch` /\n * browser / test-double implementations all satisfy this.\n */\nexport type DiscoverFetch = (\n input: string,\n init?: {\n headers?: Record<string, string>;\n signal?: AbortSignal;\n redirect?: 'follow' | 'error' | 'manual';\n }\n) => Promise<{\n ok: boolean;\n status: number;\n statusText: string;\n text(): Promise<string>;\n}>;\n\nexport interface DiscoverOptions {\n /**\n * HTTP fetch implementation. Defaults to the ambient `fetch` global.\n * Supply `undici.fetch`, a test double, or a policy-wrapping client as\n * needed.\n */\n fetchImpl?: DiscoverFetch;\n /**\n * User-agent string. Precedence (highest first): this option, the\n * `PEAC_USER_AGENT` environment variable, then `peac-disc`.\n */\n userAgent?: string;\n /** Caller-supplied abort signal. */\n signal?: AbortSignal;\n /**\n * Millisecond timeout. Ignored when `signal` is supplied (the caller\n * owns cancellation). Defaults to 5_000 when neither is provided.\n */\n timeoutMs?: number;\n /** Override the 256 KiB body cap from docs/specs/PEAC-TXT.md §6.1. */\n maxBytes?: number;\n /**\n * Redirect policy. Defaults to `error` to avoid cross-origin surprise\n * on a well-known discovery endpoint; set to `follow` explicitly if the\n * deployment relies on server-side redirects.\n */\n redirect?: 'follow' | 'error' | 'manual';\n}\n\n/**\n * Fetch and parse a remote peac.txt policy document. On success returns a\n * `ParseResult` whose `data` is the validated `peac-policy/0.1`\n * `PolicyDocument`. Legacy key-discovery lines in the fetched bytes are\n * surfaced as warnings but never populate `data`.\n */\nexport async function discover(\n origin: string,\n options: DiscoverOptions = {}\n): Promise<import('./types.js').ParseResult> {\n const fetchImpl = (options.fetchImpl ?? (globalThis as { fetch?: DiscoverFetch }).fetch) as\n | DiscoverFetch\n | undefined;\n if (typeof fetchImpl !== 'function') {\n return {\n valid: false,\n errors: [\n 'Discovery failed: no fetch implementation available (supply options.fetchImpl or provide a global fetch)',\n ],\n };\n }\n\n const envUa =\n typeof process !== 'undefined' && typeof process.env === 'object'\n ? process.env.PEAC_USER_AGENT\n : undefined;\n const userAgent = options.userAgent ?? envUa ?? DEFAULT_USER_AGENT;\n const maxBytes = options.maxBytes ?? MAX_BYTES;\n const redirect = options.redirect ?? 'error';\n\n // If the caller did not supply an AbortSignal, install a local one driven by timeoutMs.\n let localController: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let signal = options.signal;\n if (!signal) {\n localController = new AbortController();\n signal = localController.signal;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n if (timeoutMs > 0 && Number.isFinite(timeoutMs)) {\n timer = setTimeout(() => localController?.abort(), timeoutMs);\n }\n }\n\n try {\n const url = new URL(WELL_KNOWN_PATH, origin);\n const response = await fetchImpl(url.toString(), {\n headers: { 'User-Agent': userAgent },\n signal,\n redirect,\n });\n\n if (!response.ok) {\n return {\n valid: false,\n errors: [`HTTP ${response.status}: ${response.statusText}`],\n };\n }\n\n const content = await response.text();\n if (content.length > maxBytes) {\n return {\n valid: false,\n errors: [`peac.txt exceeds ${maxBytes} bytes (got ${content.length})`],\n };\n }\n const { parse } = await import('./parser.js');\n return parse(content);\n } catch (error) {\n return {\n valid: false,\n errors: [`Discovery failed: ${error instanceof Error ? error.message : String(error)}`],\n };\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peac/disc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Thin loader / validator and remote fetcher for peac.txt policy documents (peac-policy/0.1; docs/specs/PEAC-TXT.md)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@peac/policy-kit": "0.
|
|
24
|
+
"@peac/policy-kit": "0.13.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"typescript": "^5.0.0",
|