@apifuse/provider-sdk 2.2.0-beta.5 → 2.2.0-beta.50
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/AUTHORING.md +537 -33
- package/CHANGELOG.md +201 -1
- package/README.md +83 -22
- package/SUBMISSION.md +2 -2
- package/bin/apifuse-check.ts +165 -11
- package/bin/apifuse-dev.ts +57 -13
- package/bin/apifuse-migrate-operation-declaration.ts +55 -0
- package/bin/apifuse-migrate-shape.ts +202 -0
- package/bin/apifuse-pack-check.ts +22 -2
- package/bin/apifuse-pack-smoke.ts +57 -2
- package/bin/apifuse-pack-types.ts +357 -38
- package/bin/apifuse-perf.ts +14 -13
- package/bin/apifuse-record.ts +709 -72
- package/bin/apifuse-submit-check.ts +2344 -324
- package/bin/apifuse-sync-assets.ts +117 -0
- package/bin/submit-check-delimited-text.ts +50 -0
- package/dist/auth-turn/index.d.ts +3 -3
- package/dist/auth-turn/index.js +1 -1
- package/dist/auth.d.ts +14 -0
- package/dist/auth.js +67 -0
- package/dist/ceremonies/index.d.ts +16 -0
- package/dist/ceremonies/index.js +141 -36
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/commands.js +27 -0
- package/dist/cli/create.d.ts +4 -1
- package/dist/cli/create.js +42 -37
- package/dist/cli/migrate-operation-declaration.d.ts +59 -0
- package/dist/cli/migrate-operation-declaration.js +1178 -0
- package/dist/cli/migrate-operation-shape.d.ts +44 -0
- package/dist/cli/migrate-operation-shape.js +113 -0
- package/dist/cli/migrate-provider-shape.d.ts +52 -0
- package/dist/cli/migrate-provider-shape.js +578 -0
- package/dist/cli/prompt-assets.d.ts +80 -0
- package/dist/cli/prompt-assets.js +743 -0
- package/dist/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/dist/cli/templates/provider/Dockerfile.tpl +1 -1
- package/dist/cli/templates/provider/README.md.tpl +5 -5
- package/dist/cli/templates/provider/index.ts.tpl +6 -3
- package/dist/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/dist/cli/templates/provider/provider.json.tpl +6 -0
- package/dist/config/loader.d.ts +179 -16
- package/dist/config/loader.js +435 -127
- package/dist/contract-serialization.js +4 -8
- package/dist/contract-types.d.ts +12 -5
- package/dist/contract.js +24 -10
- package/dist/declaration-validation.d.ts +33 -0
- package/dist/declaration-validation.js +266 -0
- package/dist/define.d.ts +66 -29
- package/dist/define.js +778 -69
- package/dist/dev.d.ts +3 -0
- package/dist/dev.js +1 -1
- package/dist/engine.d.ts +78 -0
- package/dist/engine.js +133 -0
- package/dist/error-observability.d.ts +7 -0
- package/dist/error-observability.js +61 -0
- package/dist/error-resolution.d.ts +4 -0
- package/dist/error-resolution.js +122 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.js +40 -0
- package/dist/fixture-sanitization.d.ts +28 -0
- package/dist/fixture-sanitization.js +227 -0
- package/dist/health-scenario.d.ts +1842 -0
- package/dist/health-scenario.js +624 -0
- package/dist/index.d.ts +21 -10
- package/dist/index.js +12 -7
- package/dist/lint.d.ts +23 -11
- package/dist/lint.js +572 -69
- package/dist/native-address.d.ts +43 -0
- package/dist/native-address.js +281 -0
- package/dist/native-egress-policy.d.ts +31 -0
- package/dist/native-egress-policy.js +288 -0
- package/dist/observability.d.ts +5 -2
- package/dist/observability.js +48 -1
- package/dist/provider.d.ts +10 -2
- package/dist/provider.js +4 -1
- package/dist/runtime/auth-flow.d.ts +5 -1
- package/dist/runtime/auth-flow.js +6 -0
- package/dist/runtime/browser.d.ts +1 -0
- package/dist/runtime/browser.js +492 -49
- package/dist/runtime/cache.d.ts +1 -0
- package/dist/runtime/cache.js +169 -15
- package/dist/runtime/choice-wordlist.d.ts +9 -0
- package/dist/runtime/choice-wordlist.js +138 -0
- package/dist/runtime/choice.d.ts +13 -1
- package/dist/runtime/choice.js +490 -102
- package/dist/runtime/chrome149-header-order.d.ts +58 -0
- package/dist/runtime/chrome149-header-order.js +289 -0
- package/dist/runtime/env.js +12 -0
- package/dist/runtime/executor.d.ts +3 -2
- package/dist/runtime/executor.js +26 -25
- package/dist/runtime/http.d.ts +1 -0
- package/dist/runtime/http.js +515 -53
- package/dist/runtime/insights.js +2 -2
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +366 -8
- package/dist/runtime/native-network-errors.d.ts +33 -0
- package/dist/runtime/native-network-errors.js +69 -0
- package/dist/runtime/native-network.d.ts +96 -0
- package/dist/runtime/native-network.js +1232 -0
- package/dist/runtime/ocr.d.ts +29 -0
- package/dist/runtime/ocr.js +440 -0
- package/dist/runtime/otlp.d.ts +71 -2
- package/dist/runtime/otlp.js +397 -16
- package/dist/runtime/proxy-errors.js +6 -2
- package/dist/runtime/proxy-nodemaven.d.ts +56 -0
- package/dist/runtime/proxy-nodemaven.js +146 -0
- package/dist/runtime/proxy-telemetry.d.ts +80 -1
- package/dist/runtime/proxy-telemetry.js +154 -47
- package/dist/runtime/redirects.d.ts +29 -0
- package/dist/runtime/redirects.js +36 -0
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +4 -2
- package/dist/runtime/request-options.d.ts +68 -1
- package/dist/runtime/request-options.js +548 -0
- package/dist/runtime/resolver-config.d.ts +6 -0
- package/dist/runtime/resolver-config.js +6 -0
- package/dist/runtime/resolver-public.d.ts +1 -0
- package/dist/runtime/resolver-public.js +1 -0
- package/dist/runtime/resolver-shared.d.ts +14 -0
- package/dist/runtime/resolver-shared.js +12 -0
- package/dist/runtime/resolver-vendors/bindings.d.ts +48 -0
- package/dist/runtime/resolver-vendors/bindings.js +40 -0
- package/dist/runtime/resolver-vendors/browser.d.ts +22 -0
- package/dist/runtime/resolver-vendors/browser.js +377 -0
- package/dist/runtime/resolver-vendors/capsolver.d.ts +22 -0
- package/dist/runtime/resolver-vendors/capsolver.js +531 -0
- package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
- package/dist/runtime/resolver-vendors/hosts.js +33 -0
- package/dist/runtime/resolver-vendors/twocaptcha.d.ts +24 -0
- package/dist/runtime/resolver-vendors/twocaptcha.js +408 -0
- package/dist/runtime/resolver-vendors/types.d.ts +94 -0
- package/dist/runtime/resolver-vendors/types.js +96 -0
- package/dist/runtime/resolver.d.ts +72 -0
- package/dist/runtime/resolver.js +771 -0
- package/dist/runtime/secrets.d.ts +27 -0
- package/dist/runtime/secrets.js +51 -0
- package/dist/runtime/state.d.ts +3 -0
- package/dist/runtime/state.js +277 -71
- package/dist/runtime/stealth-cookies.d.ts +20 -0
- package/dist/runtime/stealth-cookies.js +111 -0
- package/dist/runtime/stealth.d.ts +41 -5
- package/dist/runtime/stealth.js +997 -291
- package/dist/runtime/stt.js +1 -12
- package/dist/runtime/timeout.d.ts +5 -0
- package/dist/runtime/timeout.js +12 -0
- package/dist/runtime/trace-config.d.ts +12 -0
- package/dist/runtime/trace-config.js +62 -0
- package/dist/runtime/trace.d.ts +5 -0
- package/dist/runtime/trace.js +43 -10
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/error-observability.d.ts +1 -0
- package/dist/server/error-observability.js +1 -0
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.js +2 -2
- package/dist/server/self-test-input-tokens.d.ts +2 -1
- package/dist/server/self-test-input-tokens.js +18 -14
- package/dist/server/self-test.d.ts +14 -3
- package/dist/server/self-test.js +129 -58
- package/dist/server/serve-implementation.d.ts +230 -0
- package/dist/server/serve-implementation.js +2265 -0
- package/dist/server/serve.d.ts +1 -70
- package/dist/server/serve.js +1 -1131
- package/dist/server/trace-output.d.ts +6 -0
- package/dist/server/trace-output.js +79 -0
- package/dist/server/types.d.ts +30 -5
- package/dist/server/types.js +13 -1
- package/dist/stateful/errors.d.ts +19 -0
- package/dist/stateful/errors.js +24 -0
- package/dist/stateful/http-provider-event-emitter.d.ts +40 -0
- package/dist/stateful/http-provider-event-emitter.js +237 -0
- package/dist/stateful/http-session-owner-registry.d.ts +44 -0
- package/dist/stateful/http-session-owner-registry.js +210 -0
- package/dist/stateful/index.d.ts +18 -0
- package/dist/stateful/index.js +18 -0
- package/dist/stateful/provider-event-delivery-failures.d.ts +32 -0
- package/dist/stateful/provider-event-delivery-failures.js +43 -0
- package/dist/stateful/provider-event-pipeline-metrics.d.ts +46 -0
- package/dist/stateful/provider-event-pipeline-metrics.js +48 -0
- package/dist/stateful/provider-event-pipeline.d.ts +50 -0
- package/dist/stateful/provider-event-pipeline.js +1 -0
- package/dist/stateful/provider-events.d.ts +101 -0
- package/dist/stateful/provider-events.js +289 -0
- package/dist/stateful/session-key.d.ts +15 -0
- package/dist/stateful/session-key.js +86 -0
- package/dist/stateful/stateful-provider-adapter-context.d.ts +5 -0
- package/dist/stateful/stateful-provider-adapter-context.js +42 -0
- package/dist/stateful/stateful-provider-adapter-metrics.d.ts +15 -0
- package/dist/stateful/stateful-provider-adapter-metrics.js +21 -0
- package/dist/stateful/stateful-provider-adapter.d.ts +98 -0
- package/dist/stateful/stateful-provider-adapter.js +287 -0
- package/dist/stateful/stateful-provider-observability.d.ts +62 -0
- package/dist/stateful/stateful-provider-observability.js +161 -0
- package/dist/stateful/stateful-provider-owner-forwarder.d.ts +41 -0
- package/dist/stateful/stateful-provider-owner-forwarder.js +215 -0
- package/dist/stateful/stateful-provider-runtime-context.d.ts +32 -0
- package/dist/stateful/stateful-provider-runtime-context.js +60 -0
- package/dist/stateful/stateful-provider-runtime-executor.d.ts +34 -0
- package/dist/stateful/stateful-provider-runtime-executor.js +52 -0
- package/dist/stateful/stateful-provider-session-routing.d.ts +67 -0
- package/dist/stateful/stateful-provider-session-routing.js +345 -0
- package/dist/stateful/stateful-provider-session-runtime.d.ts +98 -0
- package/dist/stateful/stateful-provider-session-runtime.js +245 -0
- package/dist/stateful-signing.d.ts +18 -0
- package/dist/stateful-signing.js +27 -0
- package/dist/stealth/profiles.d.ts +9 -4
- package/dist/stealth/profiles.js +160 -211
- package/dist/stream-evidence.d.ts +74 -0
- package/dist/stream-evidence.js +785 -0
- package/dist/stream.js +7 -1
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/run.d.ts +32 -2
- package/dist/testing/run.js +489 -21
- package/dist/trace-sanitization.d.ts +5 -0
- package/dist/trace-sanitization.js +45 -0
- package/dist/types.d.ts +673 -131
- package/dist/types.js +1 -0
- package/package.json +45 -5
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +118 -0
- package/src/ceremonies/index.ts +189 -46
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/approval-override.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/codemod-syntax.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/connection-precedence.ts.txt +10 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/docs-conflict.ts.txt +8 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-map.ts.txt +5 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/examples-operation.ts.txt +16 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-map.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoist-all.ts.txt +31 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/hoisted-const.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/imported-spread.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-map.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-cast-tail.ts.txt +21 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-ekitan.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/inline-spread-override.ts.txt +14 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/missing-english-locale.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/no-safety.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/non-literal.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/redundant-approval.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/safety-conflict.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/stream.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/tool-router-spread.ts.txt +15 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/unparseable.ts.txt +4 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/verbatim-template.ts.txt +12 -0
- package/src/cli/commands.ts +33 -0
- package/src/cli/create.ts +50 -37
- package/src/cli/migrate-operation-declaration.ts +1654 -0
- package/src/cli/migrate-operation-shape.ts +184 -0
- package/src/cli/migrate-provider-shape.ts +772 -0
- package/src/cli/prompt-assets.ts +865 -0
- package/src/cli/templates/provider/AGENTS.md.tpl +17 -8
- package/src/cli/templates/provider/Dockerfile.tpl +1 -1
- package/src/cli/templates/provider/README.md.tpl +5 -5
- package/src/cli/templates/provider/index.ts.tpl +6 -3
- package/src/cli/templates/provider/operations/ping.ts.tpl +4 -1
- package/src/cli/templates/provider/provider.json.tpl +6 -0
- package/src/config/loader.ts +690 -163
- package/src/contract-serialization.ts +5 -7
- package/src/contract-types.ts +12 -5
- package/src/contract.ts +24 -10
- package/src/declaration-validation.ts +330 -0
- package/src/define.ts +1048 -131
- package/src/dev.ts +4 -1
- package/src/engine.ts +279 -0
- package/src/error-observability.ts +64 -0
- package/src/error-resolution.ts +127 -0
- package/src/errors.ts +68 -0
- package/src/fixture-sanitization.ts +264 -0
- package/src/health-scenario.ts +875 -0
- package/src/index.ts +220 -13
- package/src/lint.ts +698 -90
- package/src/native-address.ts +340 -0
- package/src/native-egress-policy.ts +358 -0
- package/src/observability.ts +51 -1
- package/src/provider.ts +161 -3
- package/src/runtime/auth-flow.ts +12 -0
- package/src/runtime/browser.ts +661 -63
- package/src/runtime/cache.ts +189 -14
- package/src/runtime/choice-wordlist.ts +145 -0
- package/src/runtime/choice.ts +631 -120
- package/src/runtime/chrome149-header-order.ts +330 -0
- package/src/runtime/env.ts +13 -0
- package/src/runtime/executor.ts +43 -31
- package/src/runtime/http.ts +641 -61
- package/src/runtime/insights.ts +2 -2
- package/src/runtime/instrumentation.ts +520 -15
- package/src/runtime/native-network-errors.ts +99 -0
- package/src/runtime/native-network.ts +1605 -0
- package/src/runtime/ocr.ts +523 -0
- package/src/runtime/otlp.ts +467 -21
- package/src/runtime/proxy-errors.ts +12 -4
- package/src/runtime/proxy-nodemaven.ts +221 -0
- package/src/runtime/proxy-telemetry.ts +244 -75
- package/src/runtime/redirects.ts +66 -0
- package/src/runtime/redis.ts +7 -2
- package/src/runtime/request-options.ts +680 -1
- package/src/runtime/resolver-config.ts +6 -0
- package/src/runtime/resolver-public.ts +23 -0
- package/src/runtime/resolver-shared.ts +33 -0
- package/src/runtime/resolver-vendors/bindings.ts +56 -0
- package/src/runtime/resolver-vendors/browser.ts +533 -0
- package/src/runtime/resolver-vendors/capsolver.ts +707 -0
- package/src/runtime/resolver-vendors/hosts.ts +38 -0
- package/src/runtime/resolver-vendors/twocaptcha.ts +540 -0
- package/src/runtime/resolver-vendors/types.ts +212 -0
- package/src/runtime/resolver.ts +1157 -0
- package/src/runtime/secrets.ts +64 -0
- package/src/runtime/state.ts +394 -77
- package/src/runtime/stealth-cookies.ts +132 -0
- package/src/runtime/stealth.ts +1280 -336
- package/src/runtime/stt.ts +1 -19
- package/src/runtime/timeout.ts +18 -0
- package/src/runtime/trace-config.ts +78 -0
- package/src/runtime/trace.ts +57 -17
- package/src/serve.ts +6 -1
- package/src/server/error-observability.ts +1 -0
- package/src/server/index.ts +34 -2
- package/src/server/self-test-input-tokens.ts +29 -14
- package/src/server/self-test.ts +191 -68
- package/src/server/serve-implementation.ts +3378 -0
- package/src/server/serve.ts +1 -1632
- package/src/server/trace-output.ts +129 -0
- package/src/server/types.ts +13 -1
- package/src/stateful/README.md +146 -0
- package/src/stateful/errors.ts +35 -0
- package/src/stateful/http-provider-event-emitter.ts +314 -0
- package/src/stateful/http-session-owner-registry.ts +306 -0
- package/src/stateful/index.ts +18 -0
- package/src/stateful/provider-event-delivery-failures.ts +80 -0
- package/src/stateful/provider-event-pipeline-metrics.ts +95 -0
- package/src/stateful/provider-event-pipeline.ts +61 -0
- package/src/stateful/provider-events.ts +462 -0
- package/src/stateful/session-key.ts +111 -0
- package/src/stateful/stateful-provider-adapter-context.ts +59 -0
- package/src/stateful/stateful-provider-adapter-metrics.ts +48 -0
- package/src/stateful/stateful-provider-adapter.ts +562 -0
- package/src/stateful/stateful-provider-observability.ts +261 -0
- package/src/stateful/stateful-provider-owner-forwarder.ts +287 -0
- package/src/stateful/stateful-provider-runtime-context.ts +92 -0
- package/src/stateful/stateful-provider-runtime-executor.ts +96 -0
- package/src/stateful/stateful-provider-session-routing.ts +546 -0
- package/src/stateful/stateful-provider-session-runtime.ts +403 -0
- package/src/stateful-signing.ts +46 -0
- package/src/stealth/profiles.ts +202 -231
- package/src/stream-evidence.ts +988 -0
- package/src/stream.ts +8 -1
- package/src/testing/index.ts +10 -1
- package/src/testing/run.ts +658 -15
- package/src/trace-sanitization.ts +63 -0
- package/src/types.ts +788 -174
- package/dist/cli/templates/provider/CLAUDE.md.tpl +0 -1
- package/src/cli/templates/provider/CLAUDE.md.tpl +0 -1
- /package/dist/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/dist/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/fixtures-and-recording/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/health-checks-and-fail-closed/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/normalization-standards/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/pagination-and-counts/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-contract-verification/SKILL.md.tpl +0 -0
- /package/src/cli/templates/provider/{skills → .agents/skills}/upstream-notes/README.md.tpl +0 -0
package/src/runtime/cache.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
1
|
+
import { createHash, createHmac } from "node:crypto";
|
|
2
2
|
|
|
3
3
|
import { providerCacheRedisUrlFromEnv } from "../config/loader.js";
|
|
4
|
+
import { ProviderError } from "../errors.js";
|
|
4
5
|
import type {
|
|
5
6
|
ProviderCache,
|
|
6
7
|
ProviderCacheGetOrSetOptions,
|
|
@@ -43,9 +44,12 @@ export type ProviderCacheOptions = {
|
|
|
43
44
|
now?: () => number;
|
|
44
45
|
};
|
|
45
46
|
|
|
47
|
+
export const APIFUSE__CACHE__KEY_PEPPER_ENV = "APIFUSE__CACHE__KEY_PEPPER";
|
|
48
|
+
|
|
46
49
|
const DEFAULT_PREFIX = "apifuse:provider-cache:v1";
|
|
47
50
|
const DEFAULT_MEMORY_MAX_ENTRIES = 1_000;
|
|
48
51
|
const DEFAULT_REDIS_TIMEOUT_MS = 150;
|
|
52
|
+
const SECRET_SCOPED_KEY_MARKER = "[secret-scoped";
|
|
49
53
|
const SECRET_FIELD_NAMES = new Set([
|
|
50
54
|
"authorization",
|
|
51
55
|
"cookie",
|
|
@@ -61,6 +65,7 @@ const SECRET_FIELD_NAMES = new Set([
|
|
|
61
65
|
]);
|
|
62
66
|
|
|
63
67
|
const sharedBackends = new Map<string, SharedCacheBackend>();
|
|
68
|
+
let warnedAboutUnpepperedSecretKeys = false;
|
|
64
69
|
|
|
65
70
|
function backendKey(redisUrl: string | undefined): string {
|
|
66
71
|
return redisUrl ?? "memory";
|
|
@@ -107,19 +112,178 @@ function shouldRedactField(name: string, extra: Set<string>): boolean {
|
|
|
107
112
|
);
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
|
|
115
|
+
type NormalizedKeyPart = {
|
|
116
|
+
value: unknown;
|
|
117
|
+
secretScoped: boolean;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
function unsupportedSecretValue(path: string, reason: string): never {
|
|
121
|
+
throw new ProviderError(`Secret cache-key values must be JSON-safe; ${reason} at ${path}.`, {
|
|
122
|
+
code: "CACHE_KEY_SECRET_VALUE_UNSUPPORTED",
|
|
123
|
+
fix: "Convert the secret cache-key selector to JSON-safe primitives, arrays, or plain objects.",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function assertJsonSafeSecretValue(
|
|
128
|
+
value: unknown,
|
|
129
|
+
reportedPath: string,
|
|
130
|
+
ancestors = new Set<object>(),
|
|
131
|
+
): void {
|
|
132
|
+
if (value === undefined) return;
|
|
133
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
134
|
+
if (typeof value === "number") {
|
|
135
|
+
if (!Number.isFinite(value))
|
|
136
|
+
unsupportedSecretValue(reportedPath, "non-finite numbers are unsupported");
|
|
137
|
+
if (Object.is(value, -0))
|
|
138
|
+
unsupportedSecretValue(reportedPath, "negative zero is unsupported");
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (typeof value !== "object") {
|
|
142
|
+
unsupportedSecretValue(reportedPath, `${typeof value} values are unsupported`);
|
|
143
|
+
}
|
|
144
|
+
if (ancestors.has(value))
|
|
145
|
+
unsupportedSecretValue(reportedPath, "cyclic values are unsupported");
|
|
146
|
+
|
|
147
|
+
ancestors.add(value);
|
|
148
|
+
try {
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
if (Object.getOwnPropertySymbols(value).length > 0) {
|
|
151
|
+
unsupportedSecretValue(reportedPath, "symbol-keyed array properties are unsupported");
|
|
152
|
+
}
|
|
153
|
+
const expectedNames = new Set(["length"]);
|
|
154
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
155
|
+
const key = String(index);
|
|
156
|
+
expectedNames.add(key);
|
|
157
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
158
|
+
if (!descriptor)
|
|
159
|
+
unsupportedSecretValue(reportedPath, "sparse arrays are unsupported");
|
|
160
|
+
if (!descriptor.enumerable || !("value" in descriptor)) {
|
|
161
|
+
unsupportedSecretValue(reportedPath, "array accessors are unsupported");
|
|
162
|
+
}
|
|
163
|
+
assertJsonSafeSecretValue(descriptor.value, reportedPath, ancestors);
|
|
164
|
+
}
|
|
165
|
+
if (Object.getOwnPropertyNames(value).some((name) => !expectedNames.has(name))) {
|
|
166
|
+
unsupportedSecretValue(reportedPath, "custom array properties are unsupported");
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const prototype = Object.getPrototypeOf(value);
|
|
172
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
173
|
+
unsupportedSecretValue(reportedPath, "non-plain objects are unsupported");
|
|
174
|
+
}
|
|
175
|
+
if (Object.getOwnPropertySymbols(value).length > 0) {
|
|
176
|
+
unsupportedSecretValue(reportedPath, "symbol-keyed properties are unsupported");
|
|
177
|
+
}
|
|
178
|
+
for (const key of Object.getOwnPropertyNames(value)) {
|
|
179
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
180
|
+
if (!descriptor?.enumerable || !("value" in descriptor)) {
|
|
181
|
+
unsupportedSecretValue(
|
|
182
|
+
reportedPath,
|
|
183
|
+
"non-enumerable properties and accessors are unsupported",
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
assertJsonSafeSecretValue(descriptor.value, reportedPath, ancestors);
|
|
187
|
+
}
|
|
188
|
+
} finally {
|
|
189
|
+
ancestors.delete(value);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function containsUndefined(value: unknown): boolean {
|
|
194
|
+
if (value === undefined) return true;
|
|
195
|
+
if (Array.isArray(value)) return value.some(containsUndefined);
|
|
196
|
+
if (isRecord(value)) return Object.values(value).some(containsUndefined);
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function tagSecretValue(value: unknown): unknown {
|
|
201
|
+
if (value === undefined) return ["undefined"];
|
|
202
|
+
if (value === null) return ["null"];
|
|
203
|
+
if (typeof value === "string") return ["string", value];
|
|
204
|
+
if (typeof value === "number") return ["number", value];
|
|
205
|
+
if (typeof value === "boolean") return ["boolean", value];
|
|
206
|
+
if (Array.isArray(value)) return ["array", value.map(tagSecretValue)];
|
|
207
|
+
return [
|
|
208
|
+
"object",
|
|
209
|
+
Object.entries(value as Record<string, unknown>).map(([key, entry]) => [
|
|
210
|
+
key,
|
|
211
|
+
tagSecretValue(entry),
|
|
212
|
+
]),
|
|
213
|
+
];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function serializeSecretValue(value: unknown): string {
|
|
217
|
+
if (!containsUndefined(value)) return JSON.stringify([value]);
|
|
218
|
+
return `undefined-v1:${JSON.stringify(tagSecretValue(value))}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function warnAboutUnpepperedSecretKey(): void {
|
|
222
|
+
if (warnedAboutUnpepperedSecretKeys) return;
|
|
223
|
+
warnedAboutUnpepperedSecretKeys = true;
|
|
224
|
+
console.warn(
|
|
225
|
+
JSON.stringify({
|
|
226
|
+
level: "warn",
|
|
227
|
+
event: "provider_cache_secret_key_unpeppered",
|
|
228
|
+
message: `Secret-bearing cache keys are using unkeyed SHA-256 because ${APIFUSE__CACHE__KEY_PEPPER_ENV} is not configured.`,
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function normalizeKeyPart(
|
|
234
|
+
value: unknown,
|
|
235
|
+
extra: Set<string>,
|
|
236
|
+
pepper: string | undefined,
|
|
237
|
+
): NormalizedKeyPart {
|
|
111
238
|
if (Array.isArray(value)) {
|
|
112
|
-
|
|
239
|
+
const entries = value.map((entry) => normalizeKeyPart(entry, extra, pepper));
|
|
240
|
+
return {
|
|
241
|
+
value: entries.map((entry) => entry.value),
|
|
242
|
+
secretScoped: entries.some((entry) => entry.secretScoped),
|
|
243
|
+
};
|
|
113
244
|
}
|
|
114
245
|
if (isRecord(value)) {
|
|
115
|
-
const normalized: Record<string, unknown> =
|
|
246
|
+
const normalized: Record<string, unknown> = Object.create(null);
|
|
247
|
+
let secretScoped = false;
|
|
116
248
|
for (const key of Object.keys(value).sort()) {
|
|
117
|
-
|
|
118
|
-
|
|
249
|
+
const part = shouldRedactField(key, extra)
|
|
250
|
+
? hashSecretValue(value[key], key, extra, pepper)
|
|
251
|
+
: normalizeKeyPart(value[key], extra, pepper);
|
|
252
|
+
normalized[key] = part.value;
|
|
253
|
+
secretScoped ||= part.secretScoped;
|
|
119
254
|
}
|
|
120
|
-
return normalized;
|
|
255
|
+
return { value: normalized, secretScoped };
|
|
256
|
+
}
|
|
257
|
+
return { value, secretScoped: false };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function hashSecretValue(
|
|
261
|
+
value: unknown,
|
|
262
|
+
fieldName: string,
|
|
263
|
+
extra: Set<string>,
|
|
264
|
+
pepper: string | undefined,
|
|
265
|
+
): NormalizedKeyPart {
|
|
266
|
+
assertJsonSafeSecretValue(value, `${fieldName} (inside secret value)`);
|
|
267
|
+
const canonical = serializeSecretValue(normalizeKeyPart(value, extra, pepper).value);
|
|
268
|
+
if (pepper === undefined) {
|
|
269
|
+
warnAboutUnpepperedSecretKey();
|
|
270
|
+
const digest = createHash("sha256").update(canonical).digest("hex");
|
|
271
|
+
return { value: `sha256:${digest}`, secretScoped: true };
|
|
121
272
|
}
|
|
122
|
-
|
|
273
|
+
const digest = createHmac("sha256", pepper).update(canonical).digest("hex");
|
|
274
|
+
return { value: `hmac-sha256:${digest}`, secretScoped: true };
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function metadataKeys(
|
|
278
|
+
events: ProviderCacheLookupMeta[],
|
|
279
|
+
secretScopedKeys: Set<string>,
|
|
280
|
+
): string[] {
|
|
281
|
+
let secretScopedIndex = 0;
|
|
282
|
+
return Array.from(new Set(events.map((event) => event.key))).map((key) => {
|
|
283
|
+
if (!secretScopedKeys.has(key)) return key;
|
|
284
|
+
secretScopedIndex += 1;
|
|
285
|
+
return `${SECRET_SCOPED_KEY_MARKER}#${secretScopedIndex}]`;
|
|
286
|
+
});
|
|
123
287
|
}
|
|
124
288
|
|
|
125
289
|
function stableHash(value: unknown): string {
|
|
@@ -198,10 +362,13 @@ async function withRedisFallback<T>(operation: () => Promise<T>): Promise<T | un
|
|
|
198
362
|
|
|
199
363
|
export function createProviderCache(options: ProviderCacheOptions): ProviderCache {
|
|
200
364
|
const redisUrl = options.redisUrl ?? providerCacheRedisUrlFromEnv();
|
|
365
|
+
const configuredPepper = process.env[APIFUSE__CACHE__KEY_PEPPER_ENV];
|
|
366
|
+
const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
|
|
201
367
|
const backend = getSharedBackend(redisUrl);
|
|
202
368
|
const memoryMaxEntries = Math.max(1, options.memoryMaxEntries ?? DEFAULT_MEMORY_MAX_ENTRIES);
|
|
203
369
|
const now = options.now ?? Date.now;
|
|
204
370
|
const events: ProviderCacheLookupMeta[] = [];
|
|
371
|
+
const secretScopedKeys = new Set<string>();
|
|
205
372
|
|
|
206
373
|
function record(meta: ProviderCacheLookupMeta): void {
|
|
207
374
|
events.push(meta);
|
|
@@ -353,8 +520,10 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
|
|
|
353
520
|
return {
|
|
354
521
|
key(namespace, parts, keyOptions?: ProviderCacheKeyOptions) {
|
|
355
522
|
const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
|
|
356
|
-
const normalized = normalizeKeyPart(parts, extra);
|
|
357
|
-
|
|
523
|
+
const normalized = normalizeKeyPart(parts, extra, pepper);
|
|
524
|
+
const key = `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized.value)}`;
|
|
525
|
+
if (normalized.secretScoped) secretScopedKeys.add(key);
|
|
526
|
+
return key;
|
|
358
527
|
},
|
|
359
528
|
|
|
360
529
|
async get<T = unknown>(key: string): Promise<ProviderCacheResult<T> | null> {
|
|
@@ -413,7 +582,7 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
|
|
|
413
582
|
return {
|
|
414
583
|
hit: events.some((event) => event.hit),
|
|
415
584
|
stale: events.some((event) => event.stale),
|
|
416
|
-
keys:
|
|
585
|
+
keys: metadataKeys(events, secretScopedKeys),
|
|
417
586
|
source: sourceSummary(events),
|
|
418
587
|
};
|
|
419
588
|
},
|
|
@@ -423,13 +592,18 @@ export function createProviderCache(options: ProviderCacheOptions): ProviderCach
|
|
|
423
592
|
export function createBypassProviderCache(
|
|
424
593
|
options: Pick<ProviderCacheOptions, "providerId">,
|
|
425
594
|
): ProviderCache {
|
|
595
|
+
const configuredPepper = process.env[APIFUSE__CACHE__KEY_PEPPER_ENV];
|
|
596
|
+
const pepper = configuredPepper && configuredPepper.length > 0 ? configuredPepper : undefined;
|
|
426
597
|
const events: ProviderCacheLookupMeta[] = [];
|
|
598
|
+
const secretScopedKeys = new Set<string>();
|
|
427
599
|
|
|
428
600
|
return {
|
|
429
601
|
key(namespace, parts, keyOptions?: ProviderCacheKeyOptions) {
|
|
430
602
|
const extra = new Set((keyOptions?.redactFields ?? []).map((field) => field.toLowerCase()));
|
|
431
|
-
const normalized = normalizeKeyPart(parts, extra);
|
|
432
|
-
|
|
603
|
+
const normalized = normalizeKeyPart(parts, extra, pepper);
|
|
604
|
+
const key = `${DEFAULT_PREFIX}:${options.providerId}:${namespace}:${stableHash(normalized.value)}`;
|
|
605
|
+
if (normalized.secretScoped) secretScopedKeys.add(key);
|
|
606
|
+
return key;
|
|
433
607
|
},
|
|
434
608
|
|
|
435
609
|
async get<T = unknown>(_key: string): Promise<ProviderCacheResult<T> | null> {
|
|
@@ -464,7 +638,7 @@ export function createBypassProviderCache(
|
|
|
464
638
|
return {
|
|
465
639
|
hit: false,
|
|
466
640
|
stale: false,
|
|
467
|
-
keys:
|
|
641
|
+
keys: metadataKeys(events, secretScopedKeys),
|
|
468
642
|
source: sourceSummary(events),
|
|
469
643
|
};
|
|
470
644
|
},
|
|
@@ -478,4 +652,5 @@ export function resetProviderCacheForTests(): void {
|
|
|
478
652
|
backend.redis?.disconnect();
|
|
479
653
|
}
|
|
480
654
|
sharedBackends.clear();
|
|
655
|
+
warnedAboutUnpepperedSecretKeys = false;
|
|
481
656
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Official EFF Short Wordlist #2, embedded unchanged from:
|
|
3
|
+
* https://www.eff.org/files/2016/09/08/eff_short_wordlist_2_0.txt
|
|
4
|
+
*
|
|
5
|
+
* The source's dice-roll column is intentionally omitted; word order is preserved.
|
|
6
|
+
*/
|
|
7
|
+
const EFF_SHORT_WORDLIST_2_TEXT = `
|
|
8
|
+
aardvark abandoned abbreviate abdomen abhorrence abiding abnormal abrasion absorbing abundant abyss
|
|
9
|
+
academy accountant acetone achiness acid acoustics acquire acrobat actress acuteness aerosol
|
|
10
|
+
aesthetic affidavit afloat afraid aftershave again agency aggressor aghast agitate agnostic
|
|
11
|
+
agonizing agreeing aidless aimlessly ajar alarmclock albatross alchemy alfalfa algae aliens
|
|
12
|
+
alkaline almanac alongside alphabet already also altitude aluminum always amazingly ambulance
|
|
13
|
+
amendment amiable ammunition amnesty amoeba amplifier amuser anagram anchor android anesthesia
|
|
14
|
+
angelfish animal anklet announcer anonymous answer antelope anxiety anyplace aorta apartment apnea
|
|
15
|
+
apostrophe apple apricot aquamarine arachnid arbitrate ardently arena argument aristocrat armchair
|
|
16
|
+
aromatic arrowhead arsonist artichoke asbestos ascend aseptic ashamed asinine asleep asocial
|
|
17
|
+
asparagus astronaut asymmetric atlas atmosphere atom atrocious attic atypical auctioneer auditorium
|
|
18
|
+
augmented auspicious automobile auxiliary avalanche avenue aviator avocado awareness awhile awkward
|
|
19
|
+
awning awoke axially azalea babbling backpack badass bagpipe bakery balancing bamboo banana
|
|
20
|
+
barracuda basket bathrobe bazooka blade blender blimp blouse blurred boatyard bobcat body bogusness
|
|
21
|
+
bohemian boiler bonnet boots borough bossiness bottle bouquet boxlike breath briefcase broom
|
|
22
|
+
brushes bubblegum buckle buddhist buffalo bullfrog bunny busboy buzzard cabin cactus cadillac
|
|
23
|
+
cafeteria cage cahoots cajoling cakewalk calculator camera canister capsule carrot cashew cathedral
|
|
24
|
+
caucasian caviar ceasefire cedar celery cement census ceramics cesspool chalkboard cheesecake
|
|
25
|
+
chimney chlorine chopsticks chrome chute cilantro cinnamon circle cityscape civilian clay clergyman
|
|
26
|
+
clipboard clock clubhouse coathanger cobweb coconut codeword coexistent coffeecake cognitive
|
|
27
|
+
cohabitate collarbone computer confetti copier cornea cosmetics cotton couch coverless coyote
|
|
28
|
+
coziness crawfish crewmember crib croissant crumble crystal cubical cucumber cuddly cufflink
|
|
29
|
+
cuisine culprit cup curry cushion cuticle cybernetic cyclist cylinder cymbal cynicism cypress
|
|
30
|
+
cytoplasm dachshund daffodil dagger dairy dalmatian dandelion dartboard dastardly datebook daughter
|
|
31
|
+
dawn daytime dazzler dealer debris decal dedicate deepness defrost degree dehydrator deliverer
|
|
32
|
+
democrat dentist deodorant depot deranged desktop detergent device dexterity diamond dibs
|
|
33
|
+
dictionary diffuser digit dilated dimple dinnerware dioxide diploma directory dishcloth ditto
|
|
34
|
+
dividers dizziness doctor dodge doll dominoes donut doorstep dorsal double downstairs dozed
|
|
35
|
+
drainpipe dresser driftwood droppings drum dryer dubiously duckling duffel dugout dumpster duplex
|
|
36
|
+
durable dustpan dutiful duvet dwarfism dwelling dwindling dynamite dyslexia eagerness earlobe easel
|
|
37
|
+
eavesdrop ebook eccentric echoless eclipse ecosystem ecstasy edged editor educator eelworm eerie
|
|
38
|
+
effects eggnog egomaniac ejection elastic elbow elderly elephant elfishly eliminator elk elliptical
|
|
39
|
+
elongated elsewhere elusive elves emancipate embroidery emcee emerald emission emoticon emperor
|
|
40
|
+
emulate enactment enchilada endorphin energy enforcer engine enhance enigmatic enjoyably enlarged
|
|
41
|
+
enormous enquirer enrollment ensemble entryway enunciate envoy enzyme epidemic equipment erasable
|
|
42
|
+
ergonomic erratic eruption escalator eskimo esophagus espresso essay estrogen etching eternal
|
|
43
|
+
ethics etiquette eucalyptus eulogy euphemism euthanize evacuation evergreen evidence evolution exam
|
|
44
|
+
excerpt exerciser exfoliate exhale exist exorcist explode exquisite exterior exuberant fabric
|
|
45
|
+
factory faded failsafe falcon family fanfare fasten faucet favorite feasibly february federal
|
|
46
|
+
feedback feigned feline femur fence ferret festival fettuccine feudalist feverish fiberglass
|
|
47
|
+
fictitious fiddle figurine fillet finalist fiscally fixture flashlight fleshiness flight florist
|
|
48
|
+
flypaper foamless focus foggy folksong fondue footpath fossil fountain fox fragment freeway fridge
|
|
49
|
+
frosting fruit fryingpan gadget gainfully gallstone gamekeeper gangway garlic gaslight gathering
|
|
50
|
+
gauntlet gearbox gecko gem generator geographer gerbil gesture getaway geyser ghoulishly gibberish
|
|
51
|
+
giddiness giftshop gigabyte gimmick giraffe giveaway gizmo glasses gleeful glisten glove glucose
|
|
52
|
+
glycerin gnarly gnomish goatskin goggles goldfish gong gooey gorgeous gosling gothic gourmet
|
|
53
|
+
governor grape greyhound grill groundhog grumbling guacamole guerrilla guitar gullible gumdrop
|
|
54
|
+
gurgling gusto gutless gymnast gynecology gyration habitat hacking haggard haiku halogen hamburger
|
|
55
|
+
handgun happiness hardhat hastily hatchling haughty hazelnut headband hedgehog hefty heinously
|
|
56
|
+
helmet hemoglobin henceforth herbs hesitation hexagon hubcap huddling huff hugeness hullabaloo
|
|
57
|
+
human hunter hurricane hushing hyacinth hybrid hydrant hygienist hypnotist ibuprofen icepack icing
|
|
58
|
+
iconic identical idiocy idly igloo ignition iguana illuminate imaging imbecile imitator immigrant
|
|
59
|
+
imprint iodine ionosphere ipad iphone iridescent irksome iron irrigation island isotope issueless
|
|
60
|
+
italicize itemizer itinerary itunes ivory jabbering jackrabbit jaguar jailhouse jalapeno jamboree
|
|
61
|
+
janitor jarring jasmine jaundice jawbreaker jaywalker jazz jealous jeep jelly jeopardize jersey
|
|
62
|
+
jetski jezebel jiffy jigsaw jingling jobholder jockstrap jogging john joinable jokingly journal
|
|
63
|
+
jovial joystick jubilant judiciary juggle juice jujitsu jukebox jumpiness junkyard juror justifying
|
|
64
|
+
juvenile kabob kamikaze kangaroo karate kayak keepsake kennel kerosene ketchup khaki kickstand
|
|
65
|
+
kilogram kimono kingdom kiosk kissing kite kleenex knapsack kneecap knickers koala krypton
|
|
66
|
+
laboratory ladder lakefront lantern laptop laryngitis lasagna latch laundry lavender laxative
|
|
67
|
+
lazybones lecturer leftover leggings leisure lemon length leopard leprechaun lettuce leukemia
|
|
68
|
+
levers lewdness liability library licorice lifeboat lightbulb likewise lilac limousine lint lioness
|
|
69
|
+
lipstick liquid listless litter liverwurst lizard llama luau lubricant lucidity ludicrous luggage
|
|
70
|
+
lukewarm lullaby lumberjack lunchbox luridness luscious luxurious lyrics macaroni maestro magazine
|
|
71
|
+
mahogany maimed majority makeover malformed mammal mango mapmaker marbles massager matchstick
|
|
72
|
+
maverick maximum mayonnaise moaning mobilize moccasin modify moisture molecule momentum monastery
|
|
73
|
+
moonshine mortuary mosquito motorcycle mousetrap movie mower mozzarella muckiness mudflow mugshot
|
|
74
|
+
mule mummy mundane muppet mural mustard mutation myriad myspace myth nail namesake nanosecond
|
|
75
|
+
napkin narrator nastiness natives nautically navigate nearest nebula nectar nefarious negotiator
|
|
76
|
+
neither nemesis neoliberal nephew nervously nest netting neuron nevermore nextdoor nicotine niece
|
|
77
|
+
nimbleness nintendo nirvana nuclear nugget nuisance nullify numbing nuptials nursery nutcracker
|
|
78
|
+
nylon oasis oat obediently obituary object obliterate obnoxious observer obtain obvious occupation
|
|
79
|
+
oceanic octopus ocular office oftentimes oiliness ointment older olympics omissible omnivorous
|
|
80
|
+
oncoming onion onlooker onstage onward onyx oomph opaquely opera opium opossum opponent optical
|
|
81
|
+
opulently oscillator osmosis ostrich otherwise ought outhouse ovation oven owlish oxford oxidize
|
|
82
|
+
oxygen oyster ozone pacemaker padlock pageant pajamas palm pamphlet pantyhose paprika parakeet
|
|
83
|
+
passport patio pauper pavement payphone pebble peculiarly pedometer pegboard pelican penguin peony
|
|
84
|
+
pepperoni peroxide pesticide petroleum pewter pharmacy pheasant phonebook phrasing physician plank
|
|
85
|
+
pledge plotted plug plywood pneumonia podiatrist poetic pogo poison poking policeman poncho popcorn
|
|
86
|
+
porcupine postcard poultry powerboat prairie pretzel princess propeller prune pry pseudo psychopath
|
|
87
|
+
publisher pucker pueblo pulley pumpkin punchbowl puppy purse pushup putt puzzle pyramid python
|
|
88
|
+
quarters quesadilla quilt quote racoon radish ragweed railroad rampantly rancidity rarity raspberry
|
|
89
|
+
ravishing rearrange rebuilt receipt reentry refinery register rehydrate reimburse rejoicing
|
|
90
|
+
rekindle relic remote renovator reopen reporter request rerun reservoir retriever reunion revolver
|
|
91
|
+
rewrite rhapsody rhetoric rhino rhubarb rhyme ribbon riches ridden rigidness rimmed riptide riskily
|
|
92
|
+
ritzy riverboat roamer robe rocket romancer ropelike rotisserie roundtable royal rubber rudderless
|
|
93
|
+
rugby ruined rulebook rummage running rupture rustproof sabotage sacrifice saddlebag saffron
|
|
94
|
+
sainthood saltshaker samurai sandworm sapphire sardine sassy satchel sauna savage saxophone scarf
|
|
95
|
+
scenario schoolbook scientist scooter scrapbook sculpture scythe secretary sedative segregator
|
|
96
|
+
seismology selected semicolon senator septum sequence serpent sesame settler severely shack shelf
|
|
97
|
+
shirt shovel shrimp shuttle shyness siamese sibling siesta silicon simmering singles sisterhood
|
|
98
|
+
sitcom sixfold sizable skateboard skeleton skies skulk skylight slapping sled slingshot sloth
|
|
99
|
+
slumbering smartphone smelliness smitten smokestack smudge snapshot sneezing sniff snowsuit
|
|
100
|
+
snugness speakers sphinx spider splashing sponge sprout spur spyglass squirrel statue steamboat
|
|
101
|
+
stingray stopwatch strawberry student stylus suave subway suction suds suffocate sugar suitcase
|
|
102
|
+
sulphur superstore surfer sushi swan sweatshirt swimwear sword sycamore syllable symphony synagogue
|
|
103
|
+
syringes systemize tablespoon taco tadpole taekwondo tagalong takeout tallness tamale tanned
|
|
104
|
+
tapestry tarantula tastebud tattoo tavern thaw theater thimble thorn throat thumb thwarting tiara
|
|
105
|
+
tidbit tiebreaker tiger timid tinsel tiptoeing tirade tissue tractor tree tripod trousers trucks
|
|
106
|
+
tryout tubeless tuesday tugboat tulip tumbleweed tupperware turtle tusk tutorial tuxedo tweezers
|
|
107
|
+
twins tyrannical ultrasound umbrella umpire unarmored unbuttoned uncle underwear unevenness
|
|
108
|
+
unflavored ungloved unhinge unicycle unjustly unknown unlocking unmarked unnoticed unopened unpaved
|
|
109
|
+
unquenched unroll unscrewing untied unusual unveiled unwrinkled unyielding unzip upbeat upcountry
|
|
110
|
+
update upfront upgrade upholstery upkeep upload uppercut upright upstairs uptown upwind uranium
|
|
111
|
+
urban urchin urethane urgent urologist username usher utensil utility utmost utopia utterance
|
|
112
|
+
vacuum vagrancy valuables vanquished vaporizer varied vaseline vegetable vehicle velcro vendor
|
|
113
|
+
vertebrae vestibule veteran vexingly vicinity videogame viewfinder vigilante village vinegar violin
|
|
114
|
+
viperfish virus visor vitamins vivacious vixen vocalist vogue voicemail volleyball voucher voyage
|
|
115
|
+
vulnerable waffle wagon wakeup walrus wanderer wasp water waving wheat whisper wholesaler wick
|
|
116
|
+
widow wielder wifeless wikipedia wildcat windmill wipeout wired wishbone wizardry wobbliness
|
|
117
|
+
wolverine womb woolworker workbasket wound wrangle wreckage wristwatch wrongdoing xerox xylophone
|
|
118
|
+
yacht yahoo yard yearbook yesterday yiddish yield yo-yo yodel yogurt yuppie zealot zebra zeppelin
|
|
119
|
+
zestfully zigzagged zillion zipping zirconium zodiac zombie zookeeper zucchini
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
export const CHOICE_WORDLIST_SIZE = 1_296;
|
|
123
|
+
export const CHOICE_WORD_ENTROPY_BITS = Math.log2(CHOICE_WORDLIST_SIZE);
|
|
124
|
+
export const STANDARD_CHOICE_WORD_COUNT = 4;
|
|
125
|
+
export const HIGH_CHOICE_WORD_COUNT = 5;
|
|
126
|
+
export const STANDARD_CHOICE_ENTROPY_BITS = STANDARD_CHOICE_WORD_COUNT * CHOICE_WORD_ENTROPY_BITS;
|
|
127
|
+
export const HIGH_CHOICE_ENTROPY_BITS = HIGH_CHOICE_WORD_COUNT * CHOICE_WORD_ENTROPY_BITS;
|
|
128
|
+
|
|
129
|
+
export const EFF_SHORT_WORDLIST_2: readonly string[] = Object.freeze(
|
|
130
|
+
EFF_SHORT_WORDLIST_2_TEXT.trim().split(/\s+/),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const EFF_SHORT_WORD_SET: ReadonlySet<string> = new Set(EFF_SHORT_WORDLIST_2);
|
|
134
|
+
|
|
135
|
+
export function choiceWordAt(index: number): string {
|
|
136
|
+
const word = EFF_SHORT_WORDLIST_2[index];
|
|
137
|
+
if (word === undefined) {
|
|
138
|
+
throw new RangeError(`Choice word index is out of range: ${index}`);
|
|
139
|
+
}
|
|
140
|
+
return word;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function isChoiceWord(value: string): boolean {
|
|
144
|
+
return EFF_SHORT_WORD_SET.has(value);
|
|
145
|
+
}
|