Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into yoann/inject-browse…
Browse files Browse the repository at this point in the history
…r-sdk
  • Loading branch information
yoannmoinet committed Feb 26, 2025
2 parents 67490e1 + e115d3d commit e9d07ed
Show file tree
Hide file tree
Showing 57 changed files with 696 additions and 406 deletions.
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ packages/tests/src/plugins/error-tracking @yoannmoin
# Rum
packages/plugins/rum @yoannmoinet
packages/tests/src/plugins/rum @yoannmoinet

# Analytics
packages/plugins/analytics @yoannmoinet
packages/tests/src/plugins/analytics @yoannmoinet
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
if: steps.cache-build.outputs.cache-hit != 'true'
run: yarn build:all

- run: yarn test:unit
- run: yarn test:unit --silent

e2e:
timeout-minutes: 10
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ jobs:
env:
YARN_NPM_AUTH_TOKEN: ${{ secrets.PUBLISH_NPM_TOKEN }}
- run: yarn
- run: export BUILD_PLUGINS_ENV=production
- run: yarn publish:all
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
7 changes: 7 additions & 0 deletions LICENSES-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,13 @@ Component,Origin,Licence,Copyright
@module-federation/runtime-tools,npm,MIT,zhanghang (https://www.npmjs.com/package/@module-federation/runtime-tools)
@module-federation/sdk,npm,MIT,zhanghang (https://www.npmjs.com/package/@module-federation/sdk)
@module-federation/webpack-bundler-runtime,npm,MIT,zhanghang (https://www.npmjs.com/package/@module-federation/webpack-bundler-runtime)
@mswjs/interceptors,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/@mswjs/interceptors)
@nodelib/fs.scandir,npm,MIT,(https://www.npmjs.com/package/@nodelib/fs.scandir)
@nodelib/fs.stat,npm,MIT,(https://www.npmjs.com/package/@nodelib/fs.stat)
@nodelib/fs.walk,npm,MIT,(https://www.npmjs.com/package/@nodelib/fs.walk)
@open-draft/deferred-promise,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/@open-draft/deferred-promise)
@open-draft/logger,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/@open-draft/logger)
@open-draft/until,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/@open-draft/until)
@pkgjs/parseargs,npm,MIT,(https://github.com/pkgjs/parseargs#readme)
@pkgr/core,npm,MIT,JounQin (https://github.com/un-ts/pkgr/blob/master/packages/core)
@playwright/test,npm,Apache-2.0,Microsoft Corporation (https://playwright.dev)
Expand Down Expand Up @@ -571,6 +575,7 @@ is-generator-fn,npm,MIT,Sindre Sorhus (sindresorhus.com)
is-glob,npm,MIT,Jon Schlinkert (https://github.com/jonschlinkert/is-glob)
is-module,npm,MIT,Jonathan Ong (http://jongleberry.com)
is-negative-zero,npm,MIT,Jordan Harband (https://github.com/inspect-js/is-negative-zero)
is-node-process,npm,MIT,(https://www.npmjs.com/package/is-node-process)
is-number,npm,MIT,Jon Schlinkert (https://github.com/jonschlinkert/is-number)
is-number-object,npm,MIT,Jordan Harband (https://github.com/inspect-js/is-number-object#readme)
is-obj,npm,MIT,Sindre Sorhus (sindresorhus.com)
Expand Down Expand Up @@ -720,6 +725,7 @@ os-homedir,npm,MIT,Sindre Sorhus (sindresorhus.com)
os-tmpdir,npm,MIT,Sindre Sorhus (sindresorhus.com)
osenv,npm,ISC,Isaac Z. Schlueter (http://blog.izs.me/)
outdent,npm,MIT,Andrew Bradley (https://github.com/cspotcode/outdent#readme)
outvariant,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/outvariant)
p-finally,npm,MIT,Sindre Sorhus (sindresorhus.com)
p-limit,npm,MIT,Sindre Sorhus (sindresorhus.com)
p-locate,npm,MIT,Sindre Sorhus (sindresorhus.com)
Expand Down Expand Up @@ -856,6 +862,7 @@ stream-browserify,npm,MIT,James Halliday (https://github.com/browserify/stream-b
stream-each,npm,MIT,Mathias Buus (https://github.com/mafintosh/stream-each)
stream-http,npm,MIT,John Hiesey (https://github.com/jhiesey/stream-http#readme)
stream-shift,npm,MIT,Mathias Buus (https://github.com/mafintosh/stream-shift)
strict-event-emitter,npm,MIT,Artem Zakharchenko (https://www.npmjs.com/package/strict-event-emitter)
string_decoder,npm,MIT,(https://github.com/nodejs/string_decoder)
string-argv,npm,MIT,Anthony McCormick (https://github.com/mccormicka/string-argv)
string-length,npm,MIT,Sindre Sorhus (https://sindresorhus.com)
Expand Down
14 changes: 14 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { Env } from '@dd/core/types';

declare global {
namespace NodeJS {
interface ProcessEnv {
[key: string]: string | undefined;
BUILD_PLUGINS_ENV?: Env;
NO_CLEANUP?: '1';
NEED_BUILD?: '1';
REQUESTED_BUNDLERS?: string;
JEST_SILENT?: '1';
}
}
}
1 change: 1 addition & 0 deletions packages/core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

export const INJECTED_FILE = '__datadog-helper-file';

export const ALL_ENVS = ['development', 'production', 'test'] as const;
export const ALL_BUNDLERS = ['webpack', 'vite', 'esbuild', 'rollup', 'rspack', 'rolldown', 'farm'];
export const SUPPORTED_BUNDLERS = ['webpack', 'vite', 'esbuild', 'rollup', 'rspack'] as const;
export const FULL_NAME_BUNDLERS = [
Expand Down
129 changes: 65 additions & 64 deletions packages/core/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,77 +113,78 @@ export const ERROR_CODES_NO_RETRY = [400, 403, 413];
export const NB_RETRIES = 5;
// Do a retriable fetch.
export const doRequest = <T>(opts: RequestOpts): Promise<T> => {
const { auth, url, method = 'GET', getData, onRetry, type = 'text' } = opts;
return retry(
async (bail: (e: Error) => void, attempt: number) => {
let response: Response;
try {
const requestInit: RequestInit = {
method,
// This is needed for sending body in NodeJS' Fetch.
// https://github.com/nodejs/node/issues/46221
duplex: 'half',
};
let requestHeaders: RequestInit['headers'] = {};

// Do auth if present.
if (auth?.apiKey) {
requestHeaders['DD-API-KEY'] = auth.apiKey;
}

if (auth?.appKey) {
requestHeaders['DD-APPLICATION-KEY'] = auth.appKey;
}

if (typeof getData === 'function') {
const { data, headers } = await getData();
requestInit.body = data;
requestHeaders = { ...requestHeaders, ...headers };
}

response = await fetch(url, { ...requestInit, headers: requestHeaders });
} catch (error: any) {
// We don't want to retry if there is a non-fetch related error.
bail(error);
// bail(error) throws so the return is never executed.
return {} as T;
const { auth, url, method = 'GET', getData, type = 'text' } = opts;
const retryOpts: retry.Options = {
retries: opts.retries === 0 ? 0 : opts.retries || NB_RETRIES,
onRetry: opts.onRetry,
maxTimeout: opts.maxTimeout,
minTimeout: opts.minTimeout,
};

return retry(async (bail: (e: Error) => void, attempt: number) => {
let response: Response;
try {
const requestInit: RequestInit = {
method,
// This is needed for sending body in NodeJS' Fetch.
// https://github.com/nodejs/node/issues/46221
duplex: 'half',
};
let requestHeaders: RequestInit['headers'] = {};

// Do auth if present.
if (auth?.apiKey) {
requestHeaders['DD-API-KEY'] = auth.apiKey;
}

if (!response.ok) {
// Not instantiating the error here, as it will make Jest throw in the tests.
const errorMessage = `HTTP ${response.status} ${response.statusText}`;
if (ERROR_CODES_NO_RETRY.includes(response.status)) {
bail(new Error(errorMessage));
// bail(error) throws so the return is never executed.
return {} as T;
} else {
// Trigger the retry.
throw new Error(errorMessage);
}
if (auth?.appKey) {
requestHeaders['DD-APPLICATION-KEY'] = auth.appKey;
}

try {
let result;
// Await it so we catch any parsing error and bail.
if (type === 'json') {
result = await response.json();
} else {
result = await response.text();
}

return result as T;
} catch (error: any) {
// We don't want to retry on parsing errors.
bail(error);
if (typeof getData === 'function') {
const { data, headers } = await getData();
requestInit.body = data;
requestHeaders = { ...requestHeaders, ...headers };
}

response = await fetch(url, { ...requestInit, headers: requestHeaders });
} catch (error: any) {
// We don't want to retry if there is a non-fetch related error.
bail(error);
// bail(error) throws so the return is never executed.
return {} as T;
}

if (!response.ok) {
// Not instantiating the error here, as it will make Jest throw in the tests.
const errorMessage = `HTTP ${response.status} ${response.statusText}`;
if (ERROR_CODES_NO_RETRY.includes(response.status)) {
bail(new Error(errorMessage));
// bail(error) throws so the return is never executed.
return {} as T;
} else {
// Trigger the retry.
throw new Error(errorMessage);
}
}

try {
let result;
// Await it so we catch any parsing error and bail.
if (type === 'json') {
result = await response.json();
} else {
result = await response.text();
}
},
{
retries: NB_RETRIES,
onRetry,
},
);

return result as T;
} catch (error: any) {
// We don't want to retry on parsing errors.
bail(error);
// bail(error) throws so the return is never executed.
return {} as T;
}
}, retryOpts);
};

// Truncate a string to a certain length.
Expand Down
8 changes: 7 additions & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import type * as telemetry from '@dd/telemetry-plugin';
import type { BodyInit } from 'undici-types';
import type { UnpluginOptions } from 'unplugin';

import type { FULL_NAME_BUNDLERS, SUPPORTED_BUNDLERS } from './constants';
import type { ALL_ENVS, FULL_NAME_BUNDLERS, SUPPORTED_BUNDLERS } from './constants';

export type Assign<A, B> = Omit<A, keyof B> & B;
export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
Expand Down Expand Up @@ -104,15 +104,18 @@ export type Logger = {
info: (text: any) => void;
debug: (text: any) => void;
};
export type Env = (typeof ALL_ENVS)[number];
export type GlobalContext = {
auth?: AuthOptions;
inject: (item: ToInjectItem) => void;
bundler: BundlerReport;
build: BuildReport;
cwd: string;
env: Env;
getLogger: GetLogger;
git?: RepositoryData;
pluginNames: string[];
sendLog: (message: string, ctx?: any) => Promise<void>;
start: number;
version: string;
};
Expand Down Expand Up @@ -165,6 +168,9 @@ export type RequestOpts = {
getData?: () => Promise<Data> | Data;
type?: 'json' | 'text';
onRetry?: (error: Error, attempt: number) => void;
retries?: number;
minTimeout?: number;
maxTimeout?: number;
};

export type ResolvedEntry = { name?: string; resolved: string; original: string };
8 changes: 8 additions & 0 deletions packages/factory/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ This is used to aggregate all the plugins and expose them to the bundler.

<!-- #toc -->
- [Internal Plugins](#internal-plugins)
- [Analytics](#analytics)
- [Build Report](#build-report)
- [Bundler Report](#bundler-report)
- [Git](#git)
Expand All @@ -23,6 +24,13 @@ These are the plugins that are used internally by the factory.
Most of the time they will interact via the global context.

<!-- #internal-plugins-list -->
### Analytics

> Send some analytics data to Datadog internally.
#### [📝 Full documentation ➡️](/packages/plugins/analytics#readme)


### Build Report

> This will populate `context.build` with a bunch of data coming from the build.
Expand Down
1 change: 1 addition & 0 deletions packages/factory/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"dependencies": {
"@dd/core": "workspace:*",
"@dd/error-tracking-plugin": "workspace:*",
"@dd/internal-analytics-plugin": "workspace:*",
"@dd/internal-build-report-plugin": "workspace:*",
"@dd/internal-bundler-report-plugin": "workspace:*",
"@dd/internal-git-plugin": "workspace:*",
Expand Down
9 changes: 9 additions & 0 deletions packages/factory/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2019-Present Datadog, Inc.

import { ALL_ENVS } from '@dd/core/constants';
import type {
BuildReport,
BundlerFullName,
BundlerName,
Env,
FactoryMeta,
GetLogger,
GlobalContext,
Expand Down Expand Up @@ -115,6 +117,9 @@ export const getContext = ({
version: bundlerVersion,
},
};

const passedEnv: Env = (process.env.BUILD_PLUGINS_ENV as Env) || 'development';
const env: Env = ALL_ENVS.includes(passedEnv) ? passedEnv : 'development';
const context: GlobalContext = {
auth: options.auth,
pluginNames: [],
Expand All @@ -126,11 +131,15 @@ export const getContext = ({
build,
// This will be updated in the bundler-report plugin once we have the configuration.
cwd,
env,
getLogger: getLoggerFactory(build, options.logLevel),
// This will be updated in the injection plugin on initialization.
inject: () => {
throw new Error('Inject function called before it was initialized.');
},
sendLog: () => {
throw new Error('SendLog function called before it was initialized.');
},
start: Date.now(),
version,
};
Expand Down
2 changes: 2 additions & 0 deletions packages/factory/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import type { OptionsWithRum } from '@dd/rum-plugin/types';
import * as rum from '@dd/rum-plugin';
import type { OptionsWithTelemetry } from '@dd/telemetry-plugin/types';
import * as telemetry from '@dd/telemetry-plugin';
import { getAnalyticsPlugins } from '@dd/internal-analytics-plugin';
import { getBuildReportPlugins } from '@dd/internal-build-report-plugin';
import { getBundlerReportPlugins } from '@dd/internal-bundler-report-plugin';
import { getGitPlugins } from '@dd/internal-git-plugin';
Expand Down Expand Up @@ -84,6 +85,7 @@ export const buildPluginFactory = ({
const plugins: (PluginOptions | UnpluginOptions)[] = [
// Prefill with our internal plugins.
// #internal-plugins-injection-marker
...getAnalyticsPlugins(context),
...getBuildReportPlugins(context),
...getBundlerReportPlugins(context),
...getGitPlugins(options, context),
Expand Down
30 changes: 30 additions & 0 deletions packages/plugins/analytics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Analytics Plugin <!-- #omit in toc -->

Send some analytics data to Datadog internally.

It gives you acces to the `context.sendLog()` function.

```typescript
// Send a basic log.
context.sendLog('My basic log');

// Send some context with the log.
context.sendLog('My contextual log', { some: 'context' });
```

Every log already has some context to it:

```typescript
{
ddsource: string; // Name of the bundler plugin (e.g. `@datadog/webpack-plugin`).
env: Env; // Environment (e.g. `production`).
message; // The log message.
service: 'build-plugins';
bundler: {
name: string; // Name of the bundler (e.g. `webpack`).
version: string; // Version of the bundler.
};
plugins: PluginName[]; // List of the plugins/features enabled.
version: string; // Version of the plugin.
}
```
Loading

0 comments on commit e9d07ed

Please sign in to comment.