@clue-ai/cli 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/bin/clue-cli.mjs +11 -0
- package/package.json +1 -1
- package/src/contracts.mjs +1 -1
- package/src/lifecycle-init.mjs +26 -5
- package/src/public-schema.cjs +81 -0
- package/src/semantic-ci.mjs +560 -45
- package/src/setup-ai-contract.mjs +114 -0
- package/src/setup-check.mjs +174 -2
- package/src/setup-doctor.mjs +442 -0
- package/src/setup-help.mjs +23 -2
- package/src/setup-prepare.mjs +27 -0
- package/src/setup-tool.mjs +31 -7
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export const AI_SETUP_CONTRACT_VERSION =
|
|
2
|
+
"2026-05-10.frontend-adapter-contract.v8";
|
|
3
|
+
|
|
4
|
+
export const SETUP_DOCTRINE = {
|
|
5
|
+
purpose:
|
|
6
|
+
"Clue setup installs an external SDK integration so observed product facts can reach Clue's Customer Value Understanding Engine. It is not an opportunity to improve, refactor, redesign, or reinterpret the host application.",
|
|
7
|
+
minimal_diff_reason:
|
|
8
|
+
"The customer must be able to review and merge the setup diff with confidence. Extra formatting, refactors, auth rewrites, UI changes, or unrelated cleanup make the integration harder to trust.",
|
|
9
|
+
ai_decision_boundary:
|
|
10
|
+
"The AI should use repository understanding only to choose existing lifecycle boundaries for ClueInit, ClueIdentify, ClueSetAccount, and ClueLogout.",
|
|
11
|
+
deterministic_control_boundary:
|
|
12
|
+
"Everything that can be controlled mechanically should be controlled by the CLI, generated skills, documentation contract, lifecycle plan schema, and setup-check static guards.",
|
|
13
|
+
documentation_reason:
|
|
14
|
+
"SDK signatures, environment variable names, browser token behavior, and verification ownership are contracts. The AI must read the setup documents instead of relying on memory.",
|
|
15
|
+
failure_posture:
|
|
16
|
+
"When a lifecycle point, SDK package, signature, env name, or verification step is unclear, the correct output is a blocker or user_verification_pending, not a guessed implementation or a completion claim.",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const DETERMINISTIC_CONTROL_MODEL = {
|
|
20
|
+
ai_should_decide: [
|
|
21
|
+
"which existing bootstrap point owns ClueInit",
|
|
22
|
+
"which existing login/session success point owns ClueIdentify",
|
|
23
|
+
"which existing account/workspace/organization resolution point owns ClueSetAccount",
|
|
24
|
+
"which existing logout/session reset point owns ClueLogout",
|
|
25
|
+
"whether a lifecycle point is unclear and should be reported as blocked",
|
|
26
|
+
],
|
|
27
|
+
cli_should_control: [
|
|
28
|
+
"official SDK package names",
|
|
29
|
+
"official public SDK function names and supported lifecycle API set",
|
|
30
|
+
"environment variable names produced by setup and consumed by setup code",
|
|
31
|
+
"machine-owned semantic workflow generation and verification",
|
|
32
|
+
"setup-watch ownership as user-operated verification",
|
|
33
|
+
"static rejection of known unsafe wiring such as leaked secrets, wrong SDKs, blocking lifecycle calls, broad ClueTrack setup, and unsafe browser token proxy patterns",
|
|
34
|
+
"local API connectivity preflight for the four required setup hops before user-operated setup-watch",
|
|
35
|
+
"canonical frontend SDK adapter env names, token proxy path, and initialization safety checks",
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const API_CONNECTIVITY_CONTRACT = {
|
|
40
|
+
purpose:
|
|
41
|
+
"Clue setup has four distinct HTTP hops. The AI must not collapse customer-owned proxy routes and Clue-owned ingest routes into one vague browser-token endpoint.",
|
|
42
|
+
hops: {
|
|
43
|
+
client_backend_browser_token_proxy: {
|
|
44
|
+
owner: "customer_backend",
|
|
45
|
+
method: "POST",
|
|
46
|
+
path: "/api/v1/clue/browser-tokens",
|
|
47
|
+
caller: "customer_frontend_browserTokenProvider",
|
|
48
|
+
purpose:
|
|
49
|
+
"Issue a short-lived browser token without exposing CLUE_API_KEY to browser code.",
|
|
50
|
+
},
|
|
51
|
+
clue_backend_browser_token_issue: {
|
|
52
|
+
owner: "clue_backend",
|
|
53
|
+
method: "POST",
|
|
54
|
+
path: "/api/v1/ingest/browser-tokens",
|
|
55
|
+
caller: "customer_backend_browser_token_proxy",
|
|
56
|
+
purpose:
|
|
57
|
+
"Clue backend validates CLUE_API_KEY, project, environment, service key, and origin, then returns a browser token.",
|
|
58
|
+
},
|
|
59
|
+
browser_ingest: {
|
|
60
|
+
owner: "clue_backend",
|
|
61
|
+
method: "POST",
|
|
62
|
+
path: "/api/v1/ingest/browser",
|
|
63
|
+
caller: "customer_frontend_browser_sdk",
|
|
64
|
+
env_name: "NEXT_PUBLIC_CLUE_INGEST_ENDPOINT for Next.js browser code",
|
|
65
|
+
purpose:
|
|
66
|
+
"Browser SDK sends observation source events with x-clue-browser-token.",
|
|
67
|
+
},
|
|
68
|
+
backend_ingest: {
|
|
69
|
+
owner: "clue_backend",
|
|
70
|
+
method: "POST",
|
|
71
|
+
path: "/api/v1/ingest/backend",
|
|
72
|
+
caller: "customer_backend_sdk",
|
|
73
|
+
env_name: "CLUE_INGEST_ENDPOINT",
|
|
74
|
+
purpose:
|
|
75
|
+
"Backend SDK sends observation source events with server-side CLUE_API_KEY.",
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
preflight_command: "setup-doctor --local",
|
|
79
|
+
setup_watch_boundary:
|
|
80
|
+
"setup-doctor checks local API connectivity before user flows. setup-watch remains user-operated lifecycle and event-delivery verification.",
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const FRONTEND_ADAPTER_CONTRACT = {
|
|
84
|
+
purpose:
|
|
85
|
+
"Frontend SDK adapter code is part of the Clue setup contract. The AI may choose where the adapter is imported, but must not invent new token URL, env, or initialization semantics.",
|
|
86
|
+
nextjs_public_env: [
|
|
87
|
+
"NEXT_PUBLIC_CLUE_PROJECT_KEY",
|
|
88
|
+
"NEXT_PUBLIC_CLUE_ENVIRONMENT",
|
|
89
|
+
"NEXT_PUBLIC_CLUE_SERVICE_KEY",
|
|
90
|
+
"NEXT_PUBLIC_CLUE_INGEST_ENDPOINT",
|
|
91
|
+
"NEXT_PUBLIC_CLUE_BROWSER_TOKEN_ENDPOINT",
|
|
92
|
+
],
|
|
93
|
+
browser_token_proxy_path: "/api/v1/clue/browser-tokens",
|
|
94
|
+
rules: [
|
|
95
|
+
"Do not derive the Clue browser-token proxy from generic app API env names such as NEXT_PUBLIC_API_URL.",
|
|
96
|
+
"Do not mix stale browser token paths with the canonical /api/v1/clue/browser-tokens path in the same adapter.",
|
|
97
|
+
"Next.js browserTokenProvider must call NEXT_PUBLIC_CLUE_BROWSER_TOKEN_ENDPOINT, whose value is the customer backend browser-token proxy URL.",
|
|
98
|
+
"Do not call ClueInit with empty-string fallbacks for required NEXT_PUBLIC_CLUE_* values.",
|
|
99
|
+
"If a singleton guard is used, do not mark initialized=true before ClueInit has been called with required config present.",
|
|
100
|
+
"The browser token provider must send the same frontend serviceKey used by ClueInit.",
|
|
101
|
+
],
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const setupDoctrineSkillLines = () => [
|
|
105
|
+
`- Purpose: ${SETUP_DOCTRINE.purpose}`,
|
|
106
|
+
`- Minimal diff reason: ${SETUP_DOCTRINE.minimal_diff_reason}`,
|
|
107
|
+
`- AI decision boundary: ${SETUP_DOCTRINE.ai_decision_boundary}`,
|
|
108
|
+
`- Static control boundary: ${SETUP_DOCTRINE.deterministic_control_boundary}`,
|
|
109
|
+
`- Documentation reason: ${SETUP_DOCTRINE.documentation_reason}`,
|
|
110
|
+
`- Failure posture: ${SETUP_DOCTRINE.failure_posture}`,
|
|
111
|
+
`- API connectivity: ${API_CONNECTIVITY_CONTRACT.purpose}`,
|
|
112
|
+
`- Frontend adapter: ${FRONTEND_ADAPTER_CONTRACT.purpose}`,
|
|
113
|
+
`- API preflight: run ${API_CONNECTIVITY_CONTRACT.preflight_command} when local services and required env are available; do not substitute it for user-operated setup-watch.`,
|
|
114
|
+
];
|
package/src/setup-check.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
stripSourceNoise,
|
|
13
13
|
} from "./lifecycle-guard.mjs";
|
|
14
14
|
import { listAllowedSourceFiles } from "./path-policy.mjs";
|
|
15
|
+
import { AI_SETUP_CONTRACT_VERSION } from "./setup-ai-contract.mjs";
|
|
15
16
|
import { runSemanticInventory } from "./semantic-ci.mjs";
|
|
16
17
|
|
|
17
18
|
const DEFAULT_WORKFLOW_PATH = ".github/workflows/clue-semantic-snapshot.yml";
|
|
@@ -27,7 +28,7 @@ const SETUP_SKILLS = [
|
|
|
27
28
|
"clue-local-verification",
|
|
28
29
|
"clue-setup-report",
|
|
29
30
|
];
|
|
30
|
-
const SETUP_SKILL_CONTENT_VERSION =
|
|
31
|
+
const SETUP_SKILL_CONTENT_VERSION = AI_SETUP_CONTRACT_VERSION;
|
|
31
32
|
const REQUIRED_SETUP_SKILL_PHRASES = {
|
|
32
33
|
"clue-sdk-instrumentation": [
|
|
33
34
|
"Do not create no-op wrappers",
|
|
@@ -41,7 +42,13 @@ const REQUIRED_SETUP_SKILL_PHRASES = {
|
|
|
41
42
|
"Do not add `@clue-ai/browser-sdk` or backend SDK dependencies with `*` or `latest`",
|
|
42
43
|
"Whitespace-only changes are allowed only on lines directly changed for Clue SDK wiring",
|
|
43
44
|
"The local backend token endpoint is part of the customer app, not the Clue API",
|
|
44
|
-
"
|
|
45
|
+
"send the same service key used by `ClueInit`",
|
|
46
|
+
"NEXT_PUBLIC_CLUE_BROWSER_TOKEN_ENDPOINT",
|
|
47
|
+
"Do not forward `origin`, `projectKey`, or `environment` from JSON/body payload fields under server `CLUE_API_KEY`",
|
|
48
|
+
"Frontend SDK adapter code is contract-owned Clue setup wiring",
|
|
49
|
+
"Do not derive it from `NEXT_PUBLIC_API_URL`",
|
|
50
|
+
"Do not call `ClueInit` with empty-string fallbacks",
|
|
51
|
+
"do not set `initialized = true` before `ClueInit`",
|
|
45
52
|
"For Django code, use `clue-django-sdk` only after package-manager or registry verification confirms it is installable",
|
|
46
53
|
],
|
|
47
54
|
"clue-setup-audit": [
|
|
@@ -49,12 +56,18 @@ const REQUIRED_SETUP_SKILL_PHRASES = {
|
|
|
49
56
|
"Reject Django SDK setup when `clue-django-sdk` installability has not been verified",
|
|
50
57
|
"Reject ClueTrack instrumentation unless the user explicitly requested product event tracking",
|
|
51
58
|
"Reject Next.js browser/client code that reads non-public `process.env.CLUE_*` variables",
|
|
59
|
+
"Reject browser token proxy code that forwards origin, projectKey, or environment from request JSON/body under server `CLUE_API_KEY`",
|
|
60
|
+
"Reject frontend browser token providers that derive the Clue proxy URL from `NEXT_PUBLIC_API_URL`",
|
|
61
|
+
"Reject frontend adapters that mix stale browser-token paths",
|
|
62
|
+
"Reject frontend adapters that set `initialized = true` before calling `ClueInit`",
|
|
63
|
+
"Audit the setup diff against the Clue setup contract even when the code was written by another agent",
|
|
52
64
|
"Reject whitespace-only edits, import sorting, formatter churn",
|
|
53
65
|
"Reject unrelated refactors, renames, file moves",
|
|
54
66
|
"Execution agents must not approve, certify, or mark their own work complete",
|
|
55
67
|
],
|
|
56
68
|
"clue-local-verification": [
|
|
57
69
|
"`setup-check --require-sdk-lifecycle` is a static source check only",
|
|
70
|
+
"`setup-doctor --local` API connectivity preflight",
|
|
58
71
|
"Verify frontend SDK installability/import",
|
|
59
72
|
"Verify backend SDK installability/import",
|
|
60
73
|
"Do not run `npx -y @clue-ai/cli setup-watch --local` automatically",
|
|
@@ -732,7 +745,13 @@ const NEXT_PUBLIC_CLUE_NAMES = [
|
|
|
732
745
|
"CLUE_ENVIRONMENT",
|
|
733
746
|
"CLUE_SERVICE_KEY",
|
|
734
747
|
"CLUE_INGEST_ENDPOINT",
|
|
748
|
+
"CLUE_BROWSER_TOKEN_ENDPOINT",
|
|
735
749
|
];
|
|
750
|
+
const CANONICAL_BROWSER_TOKEN_PROXY_PATH = "/api/v1/clue/browser-tokens";
|
|
751
|
+
const BROWSER_TOKEN_PATH_PATTERN =
|
|
752
|
+
/\/[^"'`\s]*(?:browser[-_]?tokens?|browser[-_]?token)\b/i;
|
|
753
|
+
const GENERIC_PUBLIC_API_ENV_PATTERN =
|
|
754
|
+
/\bprocess\.env\.(?:(?:NEXT_PUBLIC|VITE|REACT_APP)_(?!CLUE_)[A-Z0-9_]*(?:API|BACKEND|BASE|URL)[A-Z0-9_]*)\b/;
|
|
736
755
|
|
|
737
756
|
const findNextLifecycleNonPublicEnvFiles = ({
|
|
738
757
|
dependencySources,
|
|
@@ -806,6 +825,86 @@ const findNextBrowserTokenProviderMissingPublicServiceKeyFiles = ({
|
|
|
806
825
|
.map((source) => source.file_path);
|
|
807
826
|
};
|
|
808
827
|
|
|
828
|
+
const findNextBrowserTokenProviderMissingPublicEndpointFiles = ({
|
|
829
|
+
dependencySources,
|
|
830
|
+
frontendSources,
|
|
831
|
+
}) => {
|
|
832
|
+
const roots = nextPackageRoots(dependencySources);
|
|
833
|
+
if (roots.length === 0) return [];
|
|
834
|
+
return frontendSources
|
|
835
|
+
.filter((source) => sourceIsUnderAnyRoot(source, roots))
|
|
836
|
+
.filter(sourceLooksLikeBrowserTokenProvider)
|
|
837
|
+
.filter(
|
|
838
|
+
(source) =>
|
|
839
|
+
!/\bprocess\.env\.NEXT_PUBLIC_CLUE_BROWSER_TOKEN_ENDPOINT\b/.test(
|
|
840
|
+
source.text,
|
|
841
|
+
),
|
|
842
|
+
)
|
|
843
|
+
.map((source) => source.file_path);
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
const browserTokenPathLiterals = (text) =>
|
|
847
|
+
[
|
|
848
|
+
...stripSourceNoise(text).matchAll(
|
|
849
|
+
/(["'`])([^"'`]*(?:browser[-_]?tokens?|browser[-_]?token)[^"'`]*)\1/gi,
|
|
850
|
+
),
|
|
851
|
+
].map((match) => match[2]);
|
|
852
|
+
|
|
853
|
+
const findBrowserTokenProviderWrongProxyPathFiles = (frontendSources) =>
|
|
854
|
+
frontendSources
|
|
855
|
+
.filter(sourceLooksLikeBrowserTokenProvider)
|
|
856
|
+
.filter((source) => {
|
|
857
|
+
const text = stripSourceNoise(source.text);
|
|
858
|
+
if (!/\bfetch\s*\(/.test(text)) return false;
|
|
859
|
+
const tokenPathLiterals = browserTokenPathLiterals(text).filter(
|
|
860
|
+
(literal) => BROWSER_TOKEN_PATH_PATTERN.test(literal),
|
|
861
|
+
);
|
|
862
|
+
if (tokenPathLiterals.length === 0) {
|
|
863
|
+
return false;
|
|
864
|
+
}
|
|
865
|
+
return tokenPathLiterals.some(
|
|
866
|
+
(literal) => !literal.includes(CANONICAL_BROWSER_TOKEN_PROXY_PATH),
|
|
867
|
+
);
|
|
868
|
+
})
|
|
869
|
+
.map((source) => source.file_path);
|
|
870
|
+
|
|
871
|
+
const findBrowserTokenProviderNonClueEndpointEnvFiles = (frontendSources) =>
|
|
872
|
+
frontendSources
|
|
873
|
+
.filter(sourceLooksLikeBrowserTokenProvider)
|
|
874
|
+
.filter((source) =>
|
|
875
|
+
GENERIC_PUBLIC_API_ENV_PATTERN.test(stripSourceNoise(source.text)),
|
|
876
|
+
)
|
|
877
|
+
.map((source) => source.file_path);
|
|
878
|
+
|
|
879
|
+
const findClueInitEmptyEnvFallbackFiles = (frontendSources) =>
|
|
880
|
+
frontendSources
|
|
881
|
+
.filter(
|
|
882
|
+
(source) =>
|
|
883
|
+
sourceImportsFrontendSdk(source) ||
|
|
884
|
+
sourceLooksLikeBrowserTokenProvider(source),
|
|
885
|
+
)
|
|
886
|
+
.filter((source) =>
|
|
887
|
+
/process\.env\.NEXT_PUBLIC_CLUE_[A-Z0-9_]+\s*(?:\?\?|\|\|)\s*(["'])\1/.test(
|
|
888
|
+
stripSourceNoise(source.text),
|
|
889
|
+
),
|
|
890
|
+
)
|
|
891
|
+
.map((source) => source.file_path);
|
|
892
|
+
|
|
893
|
+
const findFrontendInitBeforeClueInitFiles = (frontendSources) =>
|
|
894
|
+
frontendSources
|
|
895
|
+
.filter((source) => sourceImportsFrontendSdk(source))
|
|
896
|
+
.filter((source) => {
|
|
897
|
+
const text = stripSourceNoise(source.text, { stripStrings: true });
|
|
898
|
+
const initializedIndex = text.search(/\binitialized\s*=\s*true\b/);
|
|
899
|
+
const clueInitIndex = text.search(/\bClueInit\s*\(/);
|
|
900
|
+
return (
|
|
901
|
+
initializedIndex >= 0 &&
|
|
902
|
+
clueInitIndex >= 0 &&
|
|
903
|
+
initializedIndex < clueInitIndex
|
|
904
|
+
);
|
|
905
|
+
})
|
|
906
|
+
.map((source) => source.file_path);
|
|
907
|
+
|
|
809
908
|
const sourceLooksLikeBrowserTokenProxy = (source) => {
|
|
810
909
|
const text = stripSourceNoise(source.text);
|
|
811
910
|
return (
|
|
@@ -827,6 +926,43 @@ const findBrowserTokenProxyUsingBackendServiceKeyFiles = (backendSources) =>
|
|
|
827
926
|
})
|
|
828
927
|
.map((source) => source.file_path);
|
|
829
928
|
|
|
929
|
+
const bodyOriginPatterns = [
|
|
930
|
+
/\b(?:payload|body|requestBody|request_body|data|input)\.origin\b/i,
|
|
931
|
+
/\b(?:payload|body|requestBody|request_body|data|input)\s*\[\s*["']origin["']\s*\]/i,
|
|
932
|
+
/\b(?:payload|body|requestBody|request_body|data|input)\.get\s*\(\s*["']origin["']/i,
|
|
933
|
+
/["']origin["']\s*:\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
934
|
+
/\borigin\s*=\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
935
|
+
];
|
|
936
|
+
|
|
937
|
+
const bodyProjectEnvironmentPatterns = [
|
|
938
|
+
/\b(?:projectKey|project_key)\s*:\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
939
|
+
/["'](?:projectKey|project_key)["']\s*:\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
940
|
+
/\benvironment\s*:\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
941
|
+
/["']environment["']\s*:\s*(?:payload|body|requestBody|request_body|data|input)\b/i,
|
|
942
|
+
];
|
|
943
|
+
|
|
944
|
+
const findBrowserTokenProxyTrustingBodyOriginFiles = (backendSources) =>
|
|
945
|
+
backendSources
|
|
946
|
+
.filter(sourceLooksLikeBrowserTokenProxy)
|
|
947
|
+
.filter((source) => {
|
|
948
|
+
const text = stripSourceNoise(source.text);
|
|
949
|
+
return bodyOriginPatterns.some((pattern) => pattern.test(text));
|
|
950
|
+
})
|
|
951
|
+
.map((source) => source.file_path);
|
|
952
|
+
|
|
953
|
+
const findBrowserTokenProxyTrustingBodyProjectEnvironmentFiles = (
|
|
954
|
+
backendSources,
|
|
955
|
+
) =>
|
|
956
|
+
backendSources
|
|
957
|
+
.filter(sourceLooksLikeBrowserTokenProxy)
|
|
958
|
+
.filter((source) => {
|
|
959
|
+
const text = stripSourceNoise(source.text);
|
|
960
|
+
return bodyProjectEnvironmentPatterns.some((pattern) =>
|
|
961
|
+
pattern.test(text),
|
|
962
|
+
);
|
|
963
|
+
})
|
|
964
|
+
.map((source) => source.file_path);
|
|
965
|
+
|
|
830
966
|
const backendSdkSpec = (framework) =>
|
|
831
967
|
BACKEND_SDK_BY_FRAMEWORK[String(framework ?? "").toLowerCase()] ?? {
|
|
832
968
|
packages: Object.values(BACKEND_SDK_BY_FRAMEWORK).flatMap(
|
|
@@ -947,13 +1083,30 @@ const checkSdkLifecycle = ({
|
|
|
947
1083
|
findWildcardFrontendSdkDependencyFiles(dependencySources);
|
|
948
1084
|
const browserTokenProviderMissingServiceKeyFiles =
|
|
949
1085
|
findBrowserTokenProviderMissingServiceKeyFiles(frontendSources);
|
|
1086
|
+
const browserTokenProviderWrongProxyPathFiles =
|
|
1087
|
+
findBrowserTokenProviderWrongProxyPathFiles(frontendSources);
|
|
1088
|
+
const browserTokenProviderNonClueEndpointEnvFiles =
|
|
1089
|
+
findBrowserTokenProviderNonClueEndpointEnvFiles(frontendSources);
|
|
1090
|
+
const clueInitEmptyEnvFallbackFiles =
|
|
1091
|
+
findClueInitEmptyEnvFallbackFiles(frontendSources);
|
|
1092
|
+
const frontendInitBeforeClueInitFiles =
|
|
1093
|
+
findFrontendInitBeforeClueInitFiles(frontendSources);
|
|
950
1094
|
const nextBrowserTokenProviderMissingPublicServiceKeyFiles =
|
|
951
1095
|
findNextBrowserTokenProviderMissingPublicServiceKeyFiles({
|
|
952
1096
|
dependencySources,
|
|
953
1097
|
frontendSources,
|
|
954
1098
|
});
|
|
1099
|
+
const nextBrowserTokenProviderMissingPublicEndpointFiles =
|
|
1100
|
+
findNextBrowserTokenProviderMissingPublicEndpointFiles({
|
|
1101
|
+
dependencySources,
|
|
1102
|
+
frontendSources,
|
|
1103
|
+
});
|
|
955
1104
|
const browserTokenProxyUsingBackendServiceKeyFiles =
|
|
956
1105
|
findBrowserTokenProxyUsingBackendServiceKeyFiles(backendSources);
|
|
1106
|
+
const browserTokenProxyTrustingBodyOriginFiles =
|
|
1107
|
+
findBrowserTokenProxyTrustingBodyOriginFiles(backendSources);
|
|
1108
|
+
const browserTokenProxyTrustingBodyProjectEnvironmentFiles =
|
|
1109
|
+
findBrowserTokenProxyTrustingBodyProjectEnvironmentFiles(backendSources);
|
|
957
1110
|
const backendIdentityRequired =
|
|
958
1111
|
backendPresent &&
|
|
959
1112
|
/\b(login|signin|sign_in|auth|token|session)\b/i.test(backendCombined);
|
|
@@ -1014,10 +1167,22 @@ const checkSdkLifecycle = ({
|
|
|
1014
1167
|
wildcard_sdk_dependency_files: wildcardFrontendSdkDependencyFiles,
|
|
1015
1168
|
browser_token_provider_missing_service_key_files:
|
|
1016
1169
|
browserTokenProviderMissingServiceKeyFiles,
|
|
1170
|
+
browser_token_provider_wrong_proxy_path_files:
|
|
1171
|
+
browserTokenProviderWrongProxyPathFiles,
|
|
1172
|
+
browser_token_provider_non_clue_endpoint_env_files:
|
|
1173
|
+
browserTokenProviderNonClueEndpointEnvFiles,
|
|
1174
|
+
clue_init_empty_env_fallback_files: clueInitEmptyEnvFallbackFiles,
|
|
1175
|
+
frontend_init_before_clue_init_files: frontendInitBeforeClueInitFiles,
|
|
1017
1176
|
next_browser_token_provider_missing_public_service_key_files:
|
|
1018
1177
|
nextBrowserTokenProviderMissingPublicServiceKeyFiles,
|
|
1178
|
+
next_browser_token_provider_missing_public_endpoint_files:
|
|
1179
|
+
nextBrowserTokenProviderMissingPublicEndpointFiles,
|
|
1019
1180
|
browser_token_proxy_uses_backend_service_key_files:
|
|
1020
1181
|
browserTokenProxyUsingBackendServiceKeyFiles,
|
|
1182
|
+
browser_token_proxy_trusts_body_origin_files:
|
|
1183
|
+
browserTokenProxyTrustingBodyOriginFiles,
|
|
1184
|
+
browser_token_proxy_trusts_body_project_environment_files:
|
|
1185
|
+
browserTokenProxyTrustingBodyProjectEnvironmentFiles,
|
|
1021
1186
|
},
|
|
1022
1187
|
has_noop_wrapper: noOpPattern.test(combined),
|
|
1023
1188
|
component_lifecycle_init_files: componentLifecycleInitFiles,
|
|
@@ -1037,8 +1202,15 @@ const checkSdkLifecycle = ({
|
|
|
1037
1202
|
nextLifecycleNonPublicEnvFiles.length === 0 &&
|
|
1038
1203
|
wildcardFrontendSdkDependencyFiles.length === 0 &&
|
|
1039
1204
|
browserTokenProviderMissingServiceKeyFiles.length === 0 &&
|
|
1205
|
+
browserTokenProviderWrongProxyPathFiles.length === 0 &&
|
|
1206
|
+
browserTokenProviderNonClueEndpointEnvFiles.length === 0 &&
|
|
1207
|
+
clueInitEmptyEnvFallbackFiles.length === 0 &&
|
|
1208
|
+
frontendInitBeforeClueInitFiles.length === 0 &&
|
|
1040
1209
|
nextBrowserTokenProviderMissingPublicServiceKeyFiles.length === 0 &&
|
|
1210
|
+
nextBrowserTokenProviderMissingPublicEndpointFiles.length === 0 &&
|
|
1041
1211
|
browserTokenProxyUsingBackendServiceKeyFiles.length === 0 &&
|
|
1212
|
+
browserTokenProxyTrustingBodyOriginFiles.length === 0 &&
|
|
1213
|
+
browserTokenProxyTrustingBodyProjectEnvironmentFiles.length === 0 &&
|
|
1042
1214
|
!noOpPattern.test(combined) &&
|
|
1043
1215
|
componentLifecycleInitFiles.length === 0 &&
|
|
1044
1216
|
blockingLifecycleFiles.length === 0,
|