telemetry audit
This commit is contained in:
parent
fca6892f8d
commit
a3ea759c6c
1 changed files with 83 additions and 85 deletions
|
@ -2,24 +2,6 @@ import type { AstroUserConfig } from '../@types/astro.js';
|
||||||
|
|
||||||
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
const EVENT_SESSION = 'ASTRO_CLI_SESSION_STARTED';
|
||||||
|
|
||||||
interface ConfigInfo {
|
|
||||||
markdownPlugins: string[];
|
|
||||||
adapter: string | null;
|
|
||||||
integrations: string[];
|
|
||||||
trailingSlash: undefined | 'always' | 'never' | 'ignore';
|
|
||||||
build:
|
|
||||||
| undefined
|
|
||||||
| {
|
|
||||||
format: undefined | 'file' | 'directory';
|
|
||||||
};
|
|
||||||
markdown:
|
|
||||||
| undefined
|
|
||||||
| {
|
|
||||||
drafts: undefined | boolean;
|
|
||||||
syntaxHighlight: undefined | 'shiki' | 'prism' | false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface EventPayload {
|
interface EventPayload {
|
||||||
cliCommand: string;
|
cliCommand: string;
|
||||||
config?: ConfigInfo;
|
config?: ConfigInfo;
|
||||||
|
@ -28,42 +10,90 @@ interface EventPayload {
|
||||||
optionalIntegrations?: number;
|
optionalIntegrations?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const multiLevelKeys = new Set([
|
// Utility Types
|
||||||
'build',
|
type ConfigInfoShape<T> = Record<keyof T, string | boolean | string[] | undefined>;
|
||||||
'markdown',
|
type ConfigInfoNested<T> = Record<keyof T, string | boolean | string[] | undefined | object>;
|
||||||
'markdown.shikiConfig',
|
type AssertKeysEqual<X extends ConfigInfoShape<Y>, Y extends Record<keyof X, any>> = never;
|
||||||
'server',
|
type AssertKeysEqualDeep<X extends ConfigInfoNested<Y>, Y extends Record<keyof X, any>> = never;
|
||||||
'vite',
|
|
||||||
'vite.resolve',
|
|
||||||
'vite.css',
|
|
||||||
'vite.json',
|
|
||||||
'vite.server',
|
|
||||||
'vite.server.fs',
|
|
||||||
'vite.build',
|
|
||||||
'vite.preview',
|
|
||||||
'vite.optimizeDeps',
|
|
||||||
'vite.ssr',
|
|
||||||
'vite.worker',
|
|
||||||
]);
|
|
||||||
function configKeys(obj: Record<string, any> | undefined, parentKey: string): string[] {
|
|
||||||
if (!obj) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.entries(obj)
|
// Type Assertions!
|
||||||
.map(([key, value]) => {
|
// This will throw if createAnonymousConfigInfo() does not match the AstroUserConfig interface.
|
||||||
if (typeof value === 'object' && !Array.isArray(value)) {
|
// To fix: Analyze the error and update createAnonymousConfigInfo() below.
|
||||||
const localKey = parentKey ? parentKey + '.' + key : key;
|
type ConfigInfo = ReturnType<typeof createAnonymousConfigInfo>;
|
||||||
if (multiLevelKeys.has(localKey)) {
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let keys = configKeys(value, localKey).map((subkey) => key + '.' + subkey);
|
type Assertions = [
|
||||||
keys.unshift(key);
|
AssertKeysEqualDeep<ConfigInfo, Required<AstroUserConfig>>,
|
||||||
return keys;
|
AssertKeysEqual<ConfigInfo['build'], Required<NonNullable<AstroUserConfig['build']>>>,
|
||||||
}
|
AssertKeysEqual<ConfigInfo['image'], Required<NonNullable<AstroUserConfig['image']>>>,
|
||||||
}
|
AssertKeysEqual<ConfigInfo['markdown'], Required<NonNullable<AstroUserConfig['markdown']>>>,
|
||||||
|
AssertKeysEqual<
|
||||||
|
ConfigInfo['experimental'],
|
||||||
|
Required<NonNullable<AstroUserConfig['experimental']>>
|
||||||
|
>,
|
||||||
|
AssertKeysEqual<ConfigInfo['legacy'], Required<NonNullable<AstroUserConfig['legacy']>>>,
|
||||||
|
];
|
||||||
|
|
||||||
return key;
|
/**
|
||||||
})
|
* This function creates an anonymous "config info" object from the user's config.
|
||||||
.flat(1);
|
* All values are sanitized to preserve anonymity.
|
||||||
|
* Complex values should be cast to simple booleans/strings where possible.
|
||||||
|
* `undefined` means that the value is not tracked.
|
||||||
|
* This verbose implementation helps keep the implemetation up-to-date.
|
||||||
|
*/
|
||||||
|
function createAnonymousConfigInfo(userConfig?: AstroUserConfig) {
|
||||||
|
return {
|
||||||
|
adapter: userConfig?.adapter?.name ?? undefined,
|
||||||
|
build: {
|
||||||
|
format: userConfig?.build?.format,
|
||||||
|
client: undefined,
|
||||||
|
server: undefined,
|
||||||
|
assets: undefined,
|
||||||
|
assetsPrefix: undefined,
|
||||||
|
serverEntry: undefined,
|
||||||
|
redirects: undefined,
|
||||||
|
inlineStylesheets: undefined,
|
||||||
|
excludeMiddleware: undefined,
|
||||||
|
split: undefined,
|
||||||
|
},
|
||||||
|
base: undefined,
|
||||||
|
cacheDir: undefined,
|
||||||
|
compressHTML: undefined,
|
||||||
|
image: {
|
||||||
|
endpoint: undefined,
|
||||||
|
service: undefined,
|
||||||
|
domains: undefined,
|
||||||
|
remotePatterns: undefined,
|
||||||
|
},
|
||||||
|
integrations: userConfig?.integrations
|
||||||
|
?.flat()
|
||||||
|
.map((i) => i && i.name)
|
||||||
|
.filter((i) => i && i.startsWith('@astrojs/')) as string[],
|
||||||
|
markdown: {
|
||||||
|
drafts: undefined,
|
||||||
|
shikiConfig: undefined,
|
||||||
|
syntaxHighlight: userConfig?.markdown?.syntaxHighlight,
|
||||||
|
remarkPlugins: undefined,
|
||||||
|
remarkRehype: undefined,
|
||||||
|
gfm: undefined,
|
||||||
|
smartypants: undefined,
|
||||||
|
rehypePlugins: undefined,
|
||||||
|
},
|
||||||
|
outDir: undefined,
|
||||||
|
output: userConfig?.output,
|
||||||
|
publicDir: undefined,
|
||||||
|
redirects: userConfig?.redirects,
|
||||||
|
root: undefined,
|
||||||
|
scopedStyleStrategy: userConfig?.scopedStyleStrategy,
|
||||||
|
server: undefined,
|
||||||
|
site: undefined,
|
||||||
|
srcDir: undefined,
|
||||||
|
trailingSlash: userConfig?.trailingSlash,
|
||||||
|
vite: undefined,
|
||||||
|
experimental: {
|
||||||
|
optimizeHoistedScript: userConfig?.experimental?.optimizeHoistedScript,
|
||||||
|
},
|
||||||
|
legacy: {},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function eventCliSession(
|
export function eventCliSession(
|
||||||
|
@ -71,44 +101,12 @@ export function eventCliSession(
|
||||||
userConfig?: AstroUserConfig,
|
userConfig?: AstroUserConfig,
|
||||||
flags?: Record<string, any>
|
flags?: Record<string, any>
|
||||||
): { eventName: string; payload: EventPayload }[] {
|
): { eventName: string; payload: EventPayload }[] {
|
||||||
// Filter out falsy integrations
|
|
||||||
const configValues = userConfig
|
|
||||||
? {
|
|
||||||
markdownPlugins: [
|
|
||||||
...(userConfig?.markdown?.remarkPlugins?.map((p) =>
|
|
||||||
typeof p === 'string' ? p : typeof p
|
|
||||||
) ?? []),
|
|
||||||
...(userConfig?.markdown?.rehypePlugins?.map((p) =>
|
|
||||||
typeof p === 'string' ? p : typeof p
|
|
||||||
) ?? []),
|
|
||||||
] as string[],
|
|
||||||
adapter: userConfig?.adapter?.name ?? null,
|
|
||||||
integrations: (userConfig?.integrations ?? [])
|
|
||||||
.filter(Boolean)
|
|
||||||
.flat()
|
|
||||||
.map((i: any) => i?.name),
|
|
||||||
trailingSlash: userConfig?.trailingSlash,
|
|
||||||
build: userConfig?.build
|
|
||||||
? {
|
|
||||||
format: userConfig?.build?.format,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
markdown: userConfig?.markdown
|
|
||||||
? {
|
|
||||||
drafts: userConfig.markdown?.drafts,
|
|
||||||
syntaxHighlight: userConfig.markdown?.syntaxHighlight,
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
// Filter out yargs default `_` flag which is the cli command
|
// Filter out yargs default `_` flag which is the cli command
|
||||||
const cliFlags = flags ? Object.keys(flags).filter((name) => name != '_') : undefined;
|
const cliFlags = flags ? Object.keys(flags).filter((name) => name != '_') : undefined;
|
||||||
|
|
||||||
const payload: EventPayload = {
|
const payload: EventPayload = {
|
||||||
cliCommand,
|
cliCommand,
|
||||||
configKeys: userConfig ? configKeys(userConfig, '') : undefined,
|
config: createAnonymousConfigInfo(userConfig),
|
||||||
config: configValues,
|
|
||||||
flags: cliFlags,
|
flags: cliFlags,
|
||||||
};
|
};
|
||||||
return [{ eventName: EVENT_SESSION, payload }];
|
return [{ eventName: EVENT_SESSION, payload }];
|
||||||
|
|
Loading…
Reference in a new issue