@sema-agent/settings-schema 2.1.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +253 -1
- package/README.md +45 -10
- package/conformance/VERSION +1 -0
- package/conformance/baseline.json +55 -0
- package/conformance/cases/c01-entry-salvage-then-typo/expected.json +105 -0
- package/conformance/cases/c01-entry-salvage-then-typo/input.json +22 -0
- package/conformance/cases/c01-entry-salvage-then-typo/meta.json +10 -0
- package/conformance/cases/c02-hosts-clamp-stacked/expected.json +96 -0
- package/conformance/cases/c02-hosts-clamp-stacked/input.json +21 -0
- package/conformance/cases/c02-hosts-clamp-stacked/meta.json +10 -0
- package/conformance/cases/c03-literal-dotted-top-key/expected.json +112 -0
- package/conformance/cases/c03-literal-dotted-top-key/input.json +26 -0
- package/conformance/cases/c03-literal-dotted-top-key/meta.json +5 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/expected.json +77 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/input.json +18 -0
- package/conformance/cases/c04-all-bad-collection-not-salvaged/meta.json +5 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/expected.json +16 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/input.json +18 -0
- package/conformance/cases/c05-gate-domain-bad-entry-throws/meta.json +5 -0
- package/conformance/cases/c06-legacy-governance-lift/expected.json +99 -0
- package/conformance/cases/c06-legacy-governance-lift/input.json +20 -0
- package/conformance/cases/c06-legacy-governance-lift/meta.json +9 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/expected.json +72 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/input.json +43 -0
- package/conformance/cases/c07-hooks-is-not-a-config-domain/meta.json +6 -0
- package/conformance/cases/c08-limits-unknown-carried-64/expected.json +336 -0
- package/conformance/cases/c08-limits-unknown-carried-64/input.json +74 -0
- package/conformance/cases/c08-limits-unknown-carried-64/meta.json +5 -0
- package/conformance/cases/c09-limits-unknown-carried-65/expected.json +338 -0
- package/conformance/cases/c09-limits-unknown-carried-65/input.json +75 -0
- package/conformance/cases/c09-limits-unknown-carried-65/meta.json +7 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/expected.json +106 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/input.json +29 -0
- package/conformance/cases/c10-record-key-secret-redacted-twice/meta.json +13 -0
- package/conformance/cases/c11-unicode-unknown-keys/expected.json +88 -0
- package/conformance/cases/c11-unicode-unknown-keys/input.json +13 -0
- package/conformance/cases/c11-unicode-unknown-keys/meta.json +5 -0
- package/conformance/cases/c12-prototype-name-top-keys/expected.json +72 -0
- package/conformance/cases/c12-prototype-name-top-keys/input.json +20 -0
- package/conformance/cases/c12-prototype-name-top-keys/meta.json +11 -0
- package/conformance/cases/c13-models-field-null/expected.json +77 -0
- package/conformance/cases/c13-models-field-null/input.json +11 -0
- package/conformance/cases/c13-models-field-null/meta.json +5 -0
- package/conformance/cases/c14-models-field-empty-array/expected.json +72 -0
- package/conformance/cases/c14-models-field-empty-array/input.json +11 -0
- package/conformance/cases/c14-models-field-empty-array/meta.json +5 -0
- package/conformance/cases/c15-models-field-number/expected.json +77 -0
- package/conformance/cases/c15-models-field-number/input.json +11 -0
- package/conformance/cases/c15-models-field-number/meta.json +5 -0
- package/conformance/cases/c16-deep-nesting-205/expected.json +83 -0
- package/conformance/cases/c16-deep-nesting-205/input.json +421 -0
- package/conformance/cases/c16-deep-nesting-205/meta.json +5 -0
- package/conformance/cases/c17-empty-domain-file/expected.json +73 -0
- package/conformance/cases/c17-empty-domain-file/input.json +10 -0
- package/conformance/cases/c17-empty-domain-file/meta.json +5 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/expected.json +74 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/input.json +8 -0
- package/conformance/cases/c18-wire-envelope-not-an-object/meta.json +5 -0
- package/conformance/cases/c19-wire-envelope-no-version/expected.json +74 -0
- package/conformance/cases/c19-wire-envelope-no-version/input.json +13 -0
- package/conformance/cases/c19-wire-envelope-no-version/meta.json +5 -0
- package/conformance/cases/c20-governance-absent-lifts/expected.json +84 -0
- package/conformance/cases/c20-governance-absent-lifts/input.json +11 -0
- package/conformance/cases/c20-governance-absent-lifts/meta.json +9 -0
- package/conformance/cases/c21-governance-empty-object-wins/expected.json +72 -0
- package/conformance/cases/c21-governance-empty-object-wins/input.json +12 -0
- package/conformance/cases/c21-governance-empty-object-wins/meta.json +5 -0
- package/conformance/cases/c22-governance-null-throws/expected.json +16 -0
- package/conformance/cases/c22-governance-null-throws/input.json +9 -0
- package/conformance/cases/c22-governance-null-throws/meta.json +5 -0
- package/conformance/cases/c23-mixed-validity-models/expected.json +106 -0
- package/conformance/cases/c23-mixed-validity-models/input.json +27 -0
- package/conformance/cases/c23-mixed-validity-models/meta.json +9 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/expected.json +100 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/input.json +25 -0
- package/conformance/cases/c24-valid-entries-with-unknown-keys/meta.json +5 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/expected.json +89 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/input.json +24 -0
- package/conformance/cases/c25-published-roundtrip-zero-warnings/meta.json +5 -0
- package/conformance/cases/c26-hosts-array-1024/expected.json +7241 -0
- package/conformance/cases/c26-hosts-array-1024/input.json +3084 -0
- package/conformance/cases/c26-hosts-array-1024/meta.json +5 -0
- package/conformance/cases/c27-hosts-array-1025/expected.json +7248 -0
- package/conformance/cases/c27-hosts-array-1025/input.json +3087 -0
- package/conformance/cases/c27-hosts-array-1025/meta.json +5 -0
- package/conformance/cases/c28-large-document-over-1mb/expected.json +82 -0
- package/conformance/cases/c28-large-document-over-1mb/input.json +11 -0
- package/conformance/cases/c28-large-document-over-1mb/meta.json +5 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/expected.json +77 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/input.json +27 -0
- package/conformance/cases/c29-salvage-then-domain-refine-fails/meta.json +5 -0
- package/conformance/cases/c30-version-triple-a-first/expected.json +85 -0
- package/conformance/cases/c30-version-triple-a-first/input.json +18 -0
- package/conformance/cases/c30-version-triple-a-first/meta.json +5 -0
- package/conformance/cases/c31-version-triple-b-changed/expected.json +85 -0
- package/conformance/cases/c31-version-triple-b-changed/input.json +18 -0
- package/conformance/cases/c31-version-triple-b-changed/meta.json +5 -0
- package/conformance/cases/c32-version-triple-a-restored/expected.json +85 -0
- package/conformance/cases/c32-version-triple-a-restored/input.json +18 -0
- package/conformance/cases/c32-version-triple-a-restored/meta.json +5 -0
- package/conformance/cases/c33-limits-nested-carried-key/expected.json +91 -0
- package/conformance/cases/c33-limits-nested-carried-key/input.json +14 -0
- package/conformance/cases/c33-limits-nested-carried-key/meta.json +5 -0
- package/conformance/cases/c34-skills-content-vs-manifest/expected.json +160 -0
- package/conformance/cases/c34-skills-content-vs-manifest/input.json +18 -0
- package/conformance/cases/c34-skills-content-vs-manifest/meta.json +5 -0
- package/conformance/cases/c35-portable-domain-file-is-null/expected.json +76 -0
- package/conformance/cases/c35-portable-domain-file-is-null/input.json +9 -0
- package/conformance/cases/c35-portable-domain-file-is-null/meta.json +5 -0
- package/conformance/cases/c36-skills-entry-without-content/expected.json +144 -0
- package/conformance/cases/c36-skills-entry-without-content/input.json +16 -0
- package/conformance/cases/c36-skills-entry-without-content/meta.json +5 -0
- package/conformance/cases/c37-skills-field-null/expected.json +134 -0
- package/conformance/cases/c37-skills-field-null/input.json +9 -0
- package/conformance/cases/c37-skills-field-null/meta.json +5 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/expected.json +72 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/input.json +11 -0
- package/conformance/cases/c38-remote-exec-is-a-non-domain-file/meta.json +5 -0
- package/conformance/cases/c39-hidden-file-in-config-d/expected.json +72 -0
- package/conformance/cases/c39-hidden-file-in-config-d/input.json +11 -0
- package/conformance/cases/c39-hidden-file-in-config-d/meta.json +5 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/expected.json +112 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/input.json +39 -0
- package/conformance/cases/cc01-mcp-toolfaces-non-object/meta.json +8 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/expected.json +85 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/input.json +20 -0
- package/conformance/cases/cc02-mcp-source-key-is-transported/meta.json +8 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/expected.json +89 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/input.json +22 -0
- package/conformance/cases/cc03-model-compat-unknown-subkey/meta.json +8 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/expected.json +102 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/input.json +30 -0
- package/conformance/cases/cli01-model-name-nfc-vs-nfd/meta.json +9 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/expected.json +115 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/input.json +42 -0
- package/conformance/cases/cli02-control-and-zero-width-chars/meta.json +9 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/expected.json +92 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/input.json +16 -0
- package/conformance/cases/cli03-credential-pasted-into-unknown-key/meta.json +9 -0
- package/conformance/cases/cli04-env-value-with-newline/expected.json +93 -0
- package/conformance/cases/cli04-env-value-with-newline/input.json +23 -0
- package/conformance/cases/cli04-env-value-with-newline/meta.json +5 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/expected.json +109 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/input.json +30 -0
- package/conformance/cases/cli05-long-and-prefix-colliding-names/meta.json +5 -0
- package/conformance/cases/t01-absent-domain-key-not-null/expected.json +93 -0
- package/conformance/cases/t01-absent-domain-key-not-null/input.json +29 -0
- package/conformance/cases/t01-absent-domain-key-not-null/meta.json +6 -0
- package/conformance/cases/t02-entry-salvage-vs-whole-domain-refusal/expected.json +16 -0
- package/conformance/cases/t02-entry-salvage-vs-whole-domain-refusal/input.json +32 -0
- package/conformance/cases/t02-entry-salvage-vs-whole-domain-refusal/meta.json +6 -0
- package/conformance/cases/t03-prototype-name-key-not-swallowed/expected.json +107 -0
- package/conformance/cases/t03-prototype-name-key-not-swallowed/input.json +25 -0
- package/conformance/cases/t03-prototype-name-key-not-swallowed/meta.json +6 -0
- package/conformance/cases/t04-secret-literal-never-in-warning-value/expected.json +105 -0
- package/conformance/cases/t04-secret-literal-never-in-warning-value/input.json +25 -0
- package/conformance/cases/t04-secret-literal-never-in-warning-value/meta.json +14 -0
- package/conformance/cases/z01-every-domain-empty-object/expected.json +72 -0
- package/conformance/cases/z01-every-domain-empty-object/input.json +25 -0
- package/conformance/cases/z01-every-domain-empty-object/meta.json +5 -0
- package/conformance/cases/z02-every-domain-unknown-key/expected.json +228 -0
- package/conformance/cases/z02-every-domain-unknown-key/input.json +59 -0
- package/conformance/cases/z02-every-domain-unknown-key/meta.json +5 -0
- package/conformance/historical/settings-schema@1.0.0.json +1080 -0
- package/conformance/historical/settings-schema@1.10.0.json +1080 -0
- package/conformance/historical/settings-schema@1.5.0.json +1080 -0
- package/conformance/historical/settings-schema@2.0.0.json +1080 -0
- package/conformance/historical/settings-schema@2.1.0.json +1080 -0
- package/dist/api/auth.d.ts +42 -1
- package/dist/api/auth.js +71 -4
- package/dist/api/scopes.d.ts +9 -1
- package/dist/api/scopes.js +8 -2
- package/dist/config-fns.d.ts +60 -28
- package/dist/config-fns.js +94 -77
- package/dist/conformance/canonical.d.ts +36 -0
- package/dist/conformance/canonical.js +114 -0
- package/dist/conformance/contract-adapter.d.ts +20 -0
- package/dist/conformance/contract-adapter.js +74 -0
- package/dist/conformance/corpus.d.ts +73 -0
- package/dist/conformance/corpus.js +99 -0
- package/dist/conformance/derive.d.ts +48 -0
- package/dist/conformance/derive.js +136 -0
- package/dist/conformance/index.d.ts +22 -0
- package/dist/conformance/index.js +22 -0
- package/dist/conformance/run.d.ts +27 -0
- package/dist/conformance/run.js +424 -0
- package/dist/conformance/types.d.ts +288 -0
- package/dist/conformance/types.js +4 -0
- package/dist/conformance/warnings.d.ts +88 -0
- package/dist/conformance/warnings.js +144 -0
- package/dist/cross-domain.d.ts +1 -1
- package/dist/cross-domain.js +1 -1
- package/dist/file-store.d.ts +7 -0
- package/dist/file-store.js +6 -2
- package/dist/hooks.d.ts +2 -2
- package/dist/hooks.js +2 -2
- package/dist/scheduler-store.d.ts +1 -1
- package/dist/scheduler-store.js +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +3 -3
- package/package.json +7 -5
- package/dist/api/wire.d.ts +0 -60
- package/dist/api/wire.js +0 -89
package/dist/api/auth.d.ts
CHANGED
|
@@ -26,7 +26,48 @@
|
|
|
26
26
|
* Pure zod contract — zero IO, browser-safe, same rules as the rest of this package.
|
|
27
27
|
*/
|
|
28
28
|
import { z } from "zod";
|
|
29
|
-
|
|
29
|
+
/** The five auth endpoints, relative to the registry origin. */
|
|
30
|
+
export declare const AUTH_V1_PATHS: {
|
|
31
|
+
readonly deviceCode: "/api/v1/auth/device/code";
|
|
32
|
+
readonly deviceToken: "/api/v1/auth/device/token";
|
|
33
|
+
readonly deviceApprove: "/api/v1/auth/device/approve";
|
|
34
|
+
readonly tokenRefresh: "/api/v1/auth/token/refresh";
|
|
35
|
+
readonly logout: "/api/v1/auth/logout";
|
|
36
|
+
};
|
|
37
|
+
/** The RFC 8628 grant_type the device token endpoint requires. */
|
|
38
|
+
export declare const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
39
|
+
/** Minimum seconds between token-endpoint polls (RFC 8628 `interval`); polling faster → `slow_down`. */
|
|
40
|
+
export declare const DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
41
|
+
/** Device-code handshake lifetime (seconds) — the user has 15 minutes to open /activate and approve. */
|
|
42
|
+
export declare const DEVICE_CODE_TTL_SECONDS: number;
|
|
43
|
+
/** Access-token (RS256 JWT) lifetime in seconds — 1h, re-minted via refresh. */
|
|
44
|
+
export declare const ACCESS_TOKEN_TTL_SECONDS: number;
|
|
45
|
+
/** Refresh-grant lifetime (seconds) — 30d SLIDING: every rotation opens a fresh 30d window. */
|
|
46
|
+
export declare const REFRESH_TOKEN_TTL_SECONDS: number;
|
|
47
|
+
/** Every error code the /api/v1/auth/* endpoints answer (HTTP 400 unless noted). */
|
|
48
|
+
export declare const OAUTH_ERROR_CODES: readonly ["authorization_pending", "slow_down", "expired_token", "access_denied", "invalid_request", "unsupported_grant_type", "invalid_grant", "server_error"];
|
|
49
|
+
export type OAuthErrorCode = (typeof OAUTH_ERROR_CODES)[number];
|
|
50
|
+
/** Handshake states a consent-screen lookup can see. (`approved` rows vanish once exchanged/consumed.)
|
|
51
|
+
* `denied` is contract-reserved for an explicit deny button (pairs with the `access_denied` poll error);
|
|
52
|
+
* the shipped M1 store carries pending|approved only — adding deny later is implementation, not schema. */
|
|
53
|
+
export declare const DEVICE_AUTH_STATUSES: readonly ["pending", "approved", "denied"];
|
|
54
|
+
export type DeviceAuthStatus = (typeof DEVICE_AUTH_STATUSES)[number];
|
|
55
|
+
/**
|
|
56
|
+
* Canonicalize a human-typed user code to the wire shape "XXXX-XXXX": uppercase, dashes/spaces optional.
|
|
57
|
+
* null = not a plausible code (wrong length/charset after stripping separators). Same normalization the
|
|
58
|
+
* server applies — run it client-side for instant feedback.
|
|
59
|
+
*/
|
|
60
|
+
export declare function normalizeUserCode(input: unknown): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* The RFC 8628 §3.5 poll-loop step: what interval to poll with next, and whether to keep going.
|
|
63
|
+
* - authorization_pending → keep polling at the current interval
|
|
64
|
+
* - slow_down → keep polling, interval + 5s (the RFC-mandated increment)
|
|
65
|
+
* - anything else → stop (expired_token/access_denied = terminal; invalid_* = client bug)
|
|
66
|
+
*/
|
|
67
|
+
export declare function nextPollInterval(currentIntervalSeconds: number, error: OAuthErrorCode): {
|
|
68
|
+
continue: boolean;
|
|
69
|
+
intervalSeconds: number;
|
|
70
|
+
};
|
|
30
71
|
/** The uniform error body. `error_description` is HUMAN diagnostic text — clients branch on `error` only. */
|
|
31
72
|
export declare const OAuthErrorResponse: z.ZodObject<{
|
|
32
73
|
error: z.ZodEnum<["authorization_pending", "slow_down", "expired_token", "access_denied", "invalid_request", "unsupported_grant_type", "invalid_grant", "server_error"]>;
|
package/dist/api/auth.js
CHANGED
|
@@ -26,11 +26,78 @@
|
|
|
26
26
|
* Pure zod contract — zero IO, browser-safe, same rules as the rest of this package.
|
|
27
27
|
*/
|
|
28
28
|
import { z } from "zod";
|
|
29
|
-
import { OAUTH_ERROR_CODES, DEVICE_AUTH_STATUSES, DEVICE_GRANT_TYPE } from "./wire.js";
|
|
30
|
-
// ── PURE wire subset moved to ./wire.ts(server AI 接手首车 2026-07-27):零依赖客户端可
|
|
31
|
-
// `@sema-agent/settings-schema/api/wire` 运行时直取;这里 re-export 保持既有导入面字节兼容。
|
|
32
|
-
export { AUTH_V1_PATHS, DEVICE_GRANT_TYPE, DEVICE_POLL_INTERVAL_SECONDS, DEVICE_CODE_TTL_SECONDS, ACCESS_TOKEN_TTL_SECONDS, REFRESH_TOKEN_TTL_SECONDS, OAUTH_ERROR_CODES, DEVICE_AUTH_STATUSES, normalizeUserCode, nextPollInterval, } from "./wire.js";
|
|
33
29
|
// ── endpoint paths + protocol constants (shipped values) ─────────────────────────────────────────────────
|
|
30
|
+
// 3.0.0(S-321):这些常量与纯函数 2026-07-27 曾被拆去 `./api/wire` 子路径(给「零依赖客户端运行时直取」
|
|
31
|
+
// 留的门),四个消费仓自始至终零 import —— 死出口连同它的拆分一起删,常量回到它们的契约原处。
|
|
32
|
+
/** The five auth endpoints, relative to the registry origin. */
|
|
33
|
+
export const AUTH_V1_PATHS = {
|
|
34
|
+
deviceCode: "/api/v1/auth/device/code",
|
|
35
|
+
deviceToken: "/api/v1/auth/device/token",
|
|
36
|
+
deviceApprove: "/api/v1/auth/device/approve",
|
|
37
|
+
tokenRefresh: "/api/v1/auth/token/refresh",
|
|
38
|
+
logout: "/api/v1/auth/logout",
|
|
39
|
+
};
|
|
40
|
+
/** The RFC 8628 grant_type the device token endpoint requires. */
|
|
41
|
+
export const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
42
|
+
/** Minimum seconds between token-endpoint polls (RFC 8628 `interval`); polling faster → `slow_down`. */
|
|
43
|
+
export const DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
44
|
+
/** Device-code handshake lifetime (seconds) — the user has 15 minutes to open /activate and approve. */
|
|
45
|
+
export const DEVICE_CODE_TTL_SECONDS = 15 * 60;
|
|
46
|
+
/** Access-token (RS256 JWT) lifetime in seconds — 1h, re-minted via refresh. */
|
|
47
|
+
export const ACCESS_TOKEN_TTL_SECONDS = 60 * 60;
|
|
48
|
+
/** Refresh-grant lifetime (seconds) — 30d SLIDING: every rotation opens a fresh 30d window. */
|
|
49
|
+
export const REFRESH_TOKEN_TTL_SECONDS = 30 * 24 * 60 * 60;
|
|
50
|
+
/** Every error code the /api/v1/auth/* endpoints answer (HTTP 400 unless noted). */
|
|
51
|
+
export const OAUTH_ERROR_CODES = [
|
|
52
|
+
/** device/token: the user has not approved (or denied) the handshake yet — keep polling. */
|
|
53
|
+
"authorization_pending",
|
|
54
|
+
/** device/token: polling faster than `interval` — RFC 8628 §3.5: ADD 5 seconds to the interval. */
|
|
55
|
+
"slow_down",
|
|
56
|
+
/** device/token: handshake expired, unknown, or already exchanged — restart the flow.
|
|
57
|
+
* (Deliberately covers "never existed": the server does not disclose handshake existence.) */
|
|
58
|
+
"expired_token",
|
|
59
|
+
/** device/token: the user explicitly denied the handshake — stop polling, do not restart silently. */
|
|
60
|
+
"access_denied",
|
|
61
|
+
/** any endpoint: malformed body / missing required field / wrong content type. */
|
|
62
|
+
"invalid_request",
|
|
63
|
+
/** device/token: grant_type is not DEVICE_GRANT_TYPE. */
|
|
64
|
+
"unsupported_grant_type",
|
|
65
|
+
/** token/refresh + device/approve: unknown / expired / revoked / replayed token or code — no detail. */
|
|
66
|
+
"invalid_grant",
|
|
67
|
+
/** SSO not configured on the registry (HTTP 503) — a deployment problem, not a client one. */
|
|
68
|
+
"server_error",
|
|
69
|
+
];
|
|
70
|
+
/** Handshake states a consent-screen lookup can see. (`approved` rows vanish once exchanged/consumed.)
|
|
71
|
+
* `denied` is contract-reserved for an explicit deny button (pairs with the `access_denied` poll error);
|
|
72
|
+
* the shipped M1 store carries pending|approved only — adding deny later is implementation, not schema. */
|
|
73
|
+
export const DEVICE_AUTH_STATUSES = ["pending", "approved", "denied"];
|
|
74
|
+
// ── auth: pure client-side helpers(api/auth.ts 原件)────────────────────────────────────────────────────
|
|
75
|
+
/**
|
|
76
|
+
* Canonicalize a human-typed user code to the wire shape "XXXX-XXXX": uppercase, dashes/spaces optional.
|
|
77
|
+
* null = not a plausible code (wrong length/charset after stripping separators). Same normalization the
|
|
78
|
+
* server applies — run it client-side for instant feedback.
|
|
79
|
+
*/
|
|
80
|
+
export function normalizeUserCode(input) {
|
|
81
|
+
if (typeof input !== "string")
|
|
82
|
+
return null;
|
|
83
|
+
const raw = input.toUpperCase().replace(/[\s-]/g, "");
|
|
84
|
+
if (!/^[A-Z0-9]{8}$/.test(raw))
|
|
85
|
+
return null;
|
|
86
|
+
return `${raw.slice(0, 4)}-${raw.slice(4)}`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The RFC 8628 §3.5 poll-loop step: what interval to poll with next, and whether to keep going.
|
|
90
|
+
* - authorization_pending → keep polling at the current interval
|
|
91
|
+
* - slow_down → keep polling, interval + 5s (the RFC-mandated increment)
|
|
92
|
+
* - anything else → stop (expired_token/access_denied = terminal; invalid_* = client bug)
|
|
93
|
+
*/
|
|
94
|
+
export function nextPollInterval(currentIntervalSeconds, error) {
|
|
95
|
+
if (error === "authorization_pending")
|
|
96
|
+
return { continue: true, intervalSeconds: currentIntervalSeconds };
|
|
97
|
+
if (error === "slow_down")
|
|
98
|
+
return { continue: true, intervalSeconds: currentIntervalSeconds + 5 };
|
|
99
|
+
return { continue: false, intervalSeconds: currentIntervalSeconds };
|
|
100
|
+
}
|
|
34
101
|
// ── OAuth error envelope (RFC 6749 §5.2 / RFC 8628 §3.5) ─────────────────────────────────────────────────
|
|
35
102
|
/** The uniform error body. `error_description` is HUMAN diagnostic text — clients branch on `error` only. */
|
|
36
103
|
export const OAuthErrorResponse = z
|
package/dist/api/scopes.d.ts
CHANGED
|
@@ -51,7 +51,15 @@ export declare const GLOBAL_SCOPE = "global";
|
|
|
51
51
|
export declare const RESERVED_SCOPE_IDS: readonly ["global"];
|
|
52
52
|
/** Slug shape for scope ids: lowercase alphanumeric + inner dashes, 1–64 chars, no leading/trailing dash. */
|
|
53
53
|
export declare const SCOPE_ID_REGEX: RegExp;
|
|
54
|
-
|
|
54
|
+
/** The scope endpoints, relative to the registry origin. `members` needs the scope id — use scopeMembersPath. */
|
|
55
|
+
export declare const SCOPES_V1_PATHS: {
|
|
56
|
+
/** GET (list) + POST (create). */
|
|
57
|
+
readonly scopes: "/api/v1/scopes";
|
|
58
|
+
/** POST — mint a new access token bound to another scope. */
|
|
59
|
+
readonly authScope: "/api/v1/auth/scope";
|
|
60
|
+
};
|
|
61
|
+
/** The JWT claim carrying the token's active scope. OPTIONAL — absent means GLOBAL_SCOPE (tokenScopeOf). */
|
|
62
|
+
export declare const SCOPE_CLAIM = "scope";
|
|
55
63
|
/** `/api/v1/scopes/{id}/members` for PUT (upsert) and DELETE (remove). */
|
|
56
64
|
export declare function scopeMembersPath(scopeId: string): string;
|
|
57
65
|
/** True for ids the API refuses to create/delete ("global"). */
|
package/dist/api/scopes.js
CHANGED
|
@@ -54,8 +54,14 @@ export const RESERVED_SCOPE_IDS = [GLOBAL_SCOPE];
|
|
|
54
54
|
/** Slug shape for scope ids: lowercase alphanumeric + inner dashes, 1–64 chars, no leading/trailing dash. */
|
|
55
55
|
export const SCOPE_ID_REGEX = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
56
56
|
/** The scope endpoints, relative to the registry origin. `members` needs the scope id — use scopeMembersPath. */
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
export const SCOPES_V1_PATHS = {
|
|
58
|
+
/** GET (list) + POST (create). */
|
|
59
|
+
scopes: "/api/v1/scopes",
|
|
60
|
+
/** POST — mint a new access token bound to another scope. */
|
|
61
|
+
authScope: "/api/v1/auth/scope",
|
|
62
|
+
};
|
|
63
|
+
/** The JWT claim carrying the token's active scope. OPTIONAL — absent means GLOBAL_SCOPE (tokenScopeOf). */
|
|
64
|
+
export const SCOPE_CLAIM = "scope";
|
|
59
65
|
/** `/api/v1/scopes/{id}/members` for PUT (upsert) and DELETE (remove). */
|
|
60
66
|
export function scopeMembersPath(scopeId) {
|
|
61
67
|
return `${SCOPES_V1_PATHS.scopes}/${encodeURIComponent(scopeId)}/members`;
|
package/dist/config-fns.d.ts
CHANGED
|
@@ -133,9 +133,28 @@ export interface PublishedSnapshot {
|
|
|
133
133
|
export declare function emptyEffective(): EffectiveConfig;
|
|
134
134
|
/** Validate + fill defaults for a domain payload (or the schema's empty default when absent/invalid). */
|
|
135
135
|
export declare function parseDomain<K extends DomainName>(domain: K, raw: unknown): DomainConfig[K];
|
|
136
|
-
/**
|
|
136
|
+
/** 一条告警的**坐标**:从域文档根出发的段序列。字符串段 = 对象键(逐字,含 `.` 也逐字);数字段 =
|
|
137
|
+
* **数组下标**(非负整数;回写后 = 原文档下标)。今天没有任何告警指向域根,空数组不铸。
|
|
138
|
+
*
|
|
139
|
+
* 3.0.0 起取代点号串(S-323c)。串是**有损编码**:键名本来就允许含 `.`(见 {@link isReservedExtensionKey}
|
|
140
|
+
* 的分段匹配注),于是 `models.1.k` 既编码 `models[1].k`,也编码一个**字面叫 `models.1.k` 的顶层键**。
|
|
141
|
+
* 段形把「这一段是下标还是键名」这个位重新带上 —— 回写律因此从 2.1.0 的「两支文法各认各的」收成
|
|
142
|
+
* **一条**({@link rebaseWarningPaths}),段数门与规范十进制门一并删除:规则数变少。
|
|
143
|
+
*
|
|
144
|
+
* 出门(日志 / UI)走 {@link formatConfigPath} 单铸;包内不做反向解析。 */
|
|
145
|
+
export type ConfigPath = readonly (string | number)[];
|
|
146
|
+
/** 一条 {@link ConfigPath} 的出门形(日志 / UI / 人读的告警文本)—— 本包**唯一**的 stringify 点,
|
|
147
|
+
* 消费方零复述。段间 `.`;数字段十进制;字符串段{@link PLAIN_PATH_SEGMENT 能逐字出门}就逐字,否则按
|
|
148
|
+
* JSON 字符串字面量加引号(`models.1."a.b"` / `models."1".k`)—— 不加引号的话,含点的键段会与数组路径
|
|
149
|
+
* 出成同一个串、字面叫 `"1"` 的键会与下标 `1` 同形,那正是 S-323c 要消掉的二义。
|
|
150
|
+
*
|
|
151
|
+
* **刻意不提供 parse 反函数**:2.1.0 起没有任何一处把坐标读回来(回写走 `keptIndex` 那本账),给它
|
|
152
|
+
* 一个反函数就是给下一个人一条「在串上做事」的路。 */
|
|
153
|
+
export declare function formatConfigPath(p: ConfigPath): string;
|
|
154
|
+
/** 一条被丢掉的条目:`path` = 段坐标({@link ConfigPath};`["models", 3]` / `["roles", "summarize"]`),
|
|
155
|
+
* `error` 已脱敏。 */
|
|
137
156
|
export interface DroppedEntry {
|
|
138
|
-
path:
|
|
157
|
+
path: ConfigPath;
|
|
139
158
|
error: unknown;
|
|
140
159
|
}
|
|
141
160
|
/** 抢救造成的**下标位移表**:数组字段名 → 该字段压缩后每个位置的**原**下标(`kept[j]` = 压缩后第 j 条
|
|
@@ -208,7 +227,7 @@ export declare function statusRowsToPrune(rows: {
|
|
|
208
227
|
* store upgrades with zero data migration and zero gate loss. An explicitly-set governance domain WINS
|
|
209
228
|
* (its absence-of-a-key then means "center not managing", never "fall back to legacy runtime").
|
|
210
229
|
*
|
|
211
|
-
* SUNSET (
|
|
230
|
+
* SUNSET (2.0.0): removal is a **persistent-data** break — a store still carrying the 0.5 shape would lose
|
|
212
231
|
* its guardrails silently, so this arm cannot simply be deleted at a minor. It goes at the next MAJOR, with
|
|
213
232
|
* the standard persistent-data treatment (a loud refusal naming the domain + a one-time migration on the
|
|
214
233
|
* writer side), and the closing condition is observable rather than a promise: `buildEffective` now emits
|
|
@@ -232,7 +251,8 @@ export type EffectiveReadWarning = {
|
|
|
232
251
|
error: unknown;
|
|
233
252
|
}
|
|
234
253
|
/** 域文档里那些**不属于该域 schema** 的键:行为照旧(zod 非 strict = 剥掉,前向兼容不动),但点名
|
|
235
|
-
* 说出来。`keys` =
|
|
254
|
+
* 说出来。`keys` = 段坐标({@link ConfigPath};`["infraCostRates","toolCalMicroUsd"]` /
|
|
255
|
+
* `["commandPolicy",0,"typo"]`),见
|
|
236
256
|
* {@link droppedKeys} 的扫描边界。**1.5.0**:①{@link EXTENSION_NAMESPACES} 登记的扩展键(别的写者按契约
|
|
237
257
|
* 放在文档里、本包刻意不认的键,如壳写在 models 条目上的 `sema*`)**不算未知键**——既不点名也不计数;
|
|
238
258
|
* ②`keys` 有界(`DROP_SCAN_MAX_KEYS`),超界时带 `truncatedFrom`(= 真实未知键总数,与 `hosts-grandfathered`
|
|
@@ -240,33 +260,33 @@ export type EffectiveReadWarning = {
|
|
|
240
260
|
| {
|
|
241
261
|
domain: DomainName;
|
|
242
262
|
kind: "unknown-keys-dropped";
|
|
243
|
-
keys:
|
|
263
|
+
keys: ConfigPath[];
|
|
244
264
|
truncatedFrom?: number;
|
|
245
265
|
}
|
|
246
266
|
/** open-world 域(`.passthrough()`)里**已送达但本包不认识**的键:值原样到了消费方手里(承运),
|
|
247
|
-
* 但拼错的键名同样该有人说 —— 认不认归持有键表的消费方,`keys`
|
|
267
|
+
* 但拼错的键名同样该有人说 —— 认不认归持有键表的消费方,`keys` 是段坐标({@link ConfigPath})。 */
|
|
248
268
|
| {
|
|
249
269
|
domain: DomainName;
|
|
250
270
|
kind: "unknown-keys-carried";
|
|
251
|
-
keys:
|
|
271
|
+
keys: ConfigPath[];
|
|
252
272
|
truncatedFrom?: number;
|
|
253
273
|
}
|
|
254
274
|
/** 0.5 期的 runtime 文档里还带着治理三闸,而 governance 域从未被设过 —— 读侧抬升腿真生效了。
|
|
255
275
|
* `keys` = 这次抬起来的那几个键。**照旧生效,只是不再无声**:兼容窗要能关掉,前提是有人知道它还开着。
|
|
256
|
-
*
|
|
276
|
+
* 2.0.0 起。 */
|
|
257
277
|
| {
|
|
258
278
|
domain: "governance";
|
|
259
279
|
kind: "legacy-governance-lifted";
|
|
260
|
-
keys:
|
|
280
|
+
keys: ConfigPath[];
|
|
261
281
|
}
|
|
262
|
-
/** 一条**条目**没通过它自己的 entry schema,被单独丢掉了(域内其余条目照常生效)。`path` =
|
|
263
|
-
* (`models
|
|
282
|
+
/** 一条**条目**没通过它自己的 entry schema,被单独丢掉了(域内其余条目照常生效)。`path` = 段坐标
|
|
283
|
+
* (`["models",3]` / `["roles","summarize"]`),与 `unknown-keys-dropped` 的坐标形同一套。逐条一发 —— 载荷是
|
|
264
284
|
* O(域里的条目数),与被读文档同阶,不放大,故不设条数上限(有上限的是**单条**告警里的键列表)。
|
|
265
|
-
*
|
|
285
|
+
* 2.0.0 起;只可能来自 {@link DOMAIN_READ_FALLBACK} 判 `"default"` 的域,gate 域坏形仍然 throw。 */
|
|
266
286
|
| {
|
|
267
287
|
domain: DomainName;
|
|
268
288
|
kind: "entry-dropped";
|
|
269
|
-
path:
|
|
289
|
+
path: ConfigPath;
|
|
270
290
|
error: unknown;
|
|
271
291
|
}
|
|
272
292
|
/** `config.d/` 里存在、但本地读取集**永远不会读**的文件(名字不是域,或是域但不便携)。 */
|
|
@@ -277,8 +297,8 @@ export type EffectiveReadWarning = {
|
|
|
277
297
|
why: "not-a-domain" | "non-portable-domain";
|
|
278
298
|
};
|
|
279
299
|
/**
|
|
280
|
-
*
|
|
281
|
-
* 是它唯一的坐标账。
|
|
300
|
+
* 一条告警里的**段坐标**({@link ConfigPath})从「抢救压缩后的坐标」回写成「原文档的坐标」—— 纯函数,
|
|
301
|
+
* {@link EntryKeptIndex} 是它唯一的坐标账。
|
|
282
302
|
*
|
|
283
303
|
* 成案(S-323,消费方真案):整域 parse 失败后 {@link salvageEntries} 会把坏条目从数组里剔掉,之后的
|
|
284
304
|
* 诊断({@link droppedKeys} / {@link carriedUnknownKeys})是拿**压缩后**的文档做键集对比出来的,它报的
|
|
@@ -309,25 +329,37 @@ export declare function rebaseWarningPaths(w: EffectiveReadWarning, keptIndex: E
|
|
|
309
329
|
* 满额特判,四层各被下一轮复审打穿)。意图只能在**声明处**说清:写者在这里登记自己的命名空间,之后
|
|
310
330
|
* 所有未被登记的未知键都是拼错,消费方一条规则:未知键 = 错误,零特例。
|
|
311
331
|
*
|
|
312
|
-
* 登记形(分段):`at` =
|
|
332
|
+
* 登记形(分段):`at` = 父路径的**段模式**({@link ConfigPath} 的形加一个通配哨兵 {@link ANY_INDEX} =
|
|
333
|
+
* 任一数组下标,顶层 = `[]`;逐段全等,天然闭合——没有正则可以锚歪,test 有门)+ `key` = 键名前缀正则;
|
|
334
|
+
* `owner` = 写者;
|
|
313
335
|
* `since` = 契约出处。新写者/新层级来这里加行,并在 CHANGELOG 点名——这是 additive(minor)。
|
|
314
336
|
*
|
|
315
337
|
* · `models` 条目级 `sema[A-Z]…`:壳(cli)的自留字段族(`semaChannel`/`semaLabel`/`semaProbe`/`semaProbeAt`/
|
|
316
338
|
* `semaEffortDefault`/`semaVision`,壳侧 models.json 实键清单 design/cli-190c:「`sema` 前缀是壳侧自留字段的既定
|
|
317
339
|
* 约定」,**全条目级、顶层零装饰键**)。顶层 `sema*` 不在此列 ⇒ 仍是未知键(拼错或越界)。
|
|
318
340
|
*/
|
|
319
|
-
|
|
320
|
-
|
|
341
|
+
/** {@link EXTENSION_NAMESPACES} 段模式里的**通配段**:匹配任一数组下标。
|
|
342
|
+
*
|
|
343
|
+
* 刻意是 `unique symbol` 而不是一个约定字符串(如 `"#"`):文档键只可能是 `string | number`
|
|
344
|
+
* ({@link ConfigPath} 的值域),所以哨兵**不可能**与任何文档键相等 —— 通配与字面「一个叫 `#` 的键」
|
|
345
|
+
* 这两件事零二义,而且字面 `"#"` 仍然是一个可登记的普通段。类型上也不塌:`readonly (string | "#")[]`
|
|
346
|
+
* 会被 TS 收成 `readonly string[]`(写错通配不编译红),`readonly (string | typeof ANY_INDEX)[]` 不会。 */
|
|
347
|
+
export declare const ANY_INDEX: unique symbol;
|
|
348
|
+
/** {@link EXTENSION_NAMESPACES} 的一条登记:父路径段模式 + 键名前缀 + 写者 + 契约出处。 */
|
|
349
|
+
export interface ExtensionNamespaceRule {
|
|
350
|
+
readonly at: readonly (string | typeof ANY_INDEX)[];
|
|
321
351
|
readonly key: RegExp;
|
|
322
352
|
readonly owner: string;
|
|
323
353
|
readonly since: string;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
*
|
|
328
|
-
|
|
354
|
+
}
|
|
355
|
+
export declare const EXTENSION_NAMESPACES: Partial<Record<DomainName, ReadonlyArray<ExtensionNamespaceRule>>>;
|
|
356
|
+
/** 该键是否落在 {@link EXTENSION_NAMESPACES} 登记的扩展命名空间里(⇒ 不是未知键)。**分段匹配**:`at` 对
|
|
357
|
+
* 父路径的段(长度相等 ∧ 逐段——{@link ANY_INDEX} 匹配任一**数字**段,字符串段逐字相等;顶层 = `[]`),`key` 对键名
|
|
358
|
+
* 本身——键名里可以含 `.`(`semaX.foo` 是一个键不是两层),段形让这件事不必再靠文法猜;前缀契约就是前缀
|
|
359
|
+
* 契约(`semaGPT_5` / `semaX-v2` 都是成员,后缀不设未声明的文法)。 */
|
|
360
|
+
export declare function isReservedExtensionKey(domain: DomainName, parent: ConfigPath, key: string): boolean;
|
|
329
361
|
/**
|
|
330
|
-
* 一份域文档里被域 schema **丢掉的键**(zod 对象默认 `"strip"`)
|
|
362
|
+
* 一份域文档里被域 schema **丢掉的键**(zod 对象默认 `"strip"`),段坐标形({@link ConfigPath})。
|
|
331
363
|
*
|
|
332
364
|
* 成案(消费方 #322 真事故):往 `runtime` 文档里加一个不属于该域的键,两条腿都会把它剥掉,
|
|
333
365
|
* `domainErrors` 空、解析"成功"——配置写了、值没到、零告警。剥除行为本身是**刻意的前向兼容**
|
|
@@ -346,15 +378,15 @@ export declare function isReservedExtensionKey(domain: DomainName, parentPath: s
|
|
|
346
378
|
* JSON 对象——raw 若是类实例/Proxy 这类形状不扫;④ 读 raw 的值可能触发访问器,整段包 try/catch 且**绝不**
|
|
347
379
|
* 让其错误外泄(错误文案可能带 secret,与 parseDomain 的 R13 同纪律),扫描失败即当作"没看见",不影响解析。
|
|
348
380
|
*/
|
|
349
|
-
export declare function droppedKeys(domain: DomainName, raw: unknown, parsed: unknown):
|
|
381
|
+
export declare function droppedKeys(domain: DomainName, raw: unknown, parsed: unknown): ConfigPath[];
|
|
350
382
|
/**
|
|
351
|
-
* 一份已解析的 open-world 域文档里,**本包不认识但已承运**的键(
|
|
383
|
+
* 一份已解析的 open-world 域文档里,**本包不认识但已承运**的键(段坐标)。非 open-world 域恒空
|
|
352
384
|
* (它们的未知键走 {@link droppedKeys} 那条更重的「被丢了」告警)。
|
|
353
385
|
*
|
|
354
386
|
* 边界(如实):只看 {@link OPEN_WORLD_KNOWN_KEYS} 登记了的层级 —— 未登记层级(如某个未知键自己的
|
|
355
387
|
* 子树)不再下探,那本就是消费方自定义的内容,逐层猜没有意义。
|
|
356
388
|
*/
|
|
357
|
-
export declare function carriedUnknownKeys(domain: DomainName, parsed: unknown):
|
|
389
|
+
export declare function carriedUnknownKeys(domain: DomainName, parsed: unknown): ConfigPath[];
|
|
358
390
|
/**
|
|
359
391
|
* 一域的 parse + **静默剥键/静默承运两条告警**(0.19.0)。`buildEffective` 与 `FileConfigStore.getDomain`
|
|
360
392
|
* 共用这一个判据 —— 此前只有 effective 那条路径有门,而 `getDomain` 是 `exportBundle` 的读法
|
|
@@ -427,7 +459,7 @@ export interface GrandfatherHostsReadResult {
|
|
|
427
459
|
* everything else (regex, types, duplicates) is left for parseDomain — this is a targeted grandfather, not a
|
|
428
460
|
* lenient parser. PURE + idempotent; returns the ORIGINAL reference when nothing exceeds the bounds.
|
|
429
461
|
*
|
|
430
|
-
* SUNSET (
|
|
462
|
+
* SUNSET (2.0.0): same persistent-data class as the governance lift — it goes at the next MAJOR. This one was
|
|
431
463
|
* never silent (`hosts-grandfathered` fires whenever it clamps), so the closing condition is already
|
|
432
464
|
* observable: a deployment that has not seen that warning across a full read cycle no longer needs the arm. */
|
|
433
465
|
export declare function grandfatherHostsRead(raw: unknown): GrandfatherHostsReadResult;
|