feat(ui): finalize E-TIB modernization with footer redesign, video optimization, and TS fixes
Former-commit-id: 67ac02c8404cc66893fdf97308574701cca6000c
This commit is contained in:
Generated
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
|
||||
//
|
||||
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
|
||||
|
||||
const path = require('path')
|
||||
const moduleDetailsFromPath = require('module-details-from-path')
|
||||
const { fileURLToPath } = require('url')
|
||||
const { MessageChannel } = require('worker_threads')
|
||||
|
||||
let { isBuiltin } = require('module')
|
||||
if (!isBuiltin) {
|
||||
isBuiltin = () => true
|
||||
}
|
||||
|
||||
const {
|
||||
importHooks,
|
||||
specifiers,
|
||||
toHook
|
||||
} = require('./lib/register')
|
||||
|
||||
function addHook (hook) {
|
||||
importHooks.push(hook)
|
||||
toHook.forEach(([name, namespace, specifier]) => hook(name, namespace, specifier))
|
||||
}
|
||||
|
||||
function removeHook (hook) {
|
||||
const index = importHooks.indexOf(hook)
|
||||
if (index > -1) {
|
||||
importHooks.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function callHookFn (hookFn, namespace, name, baseDir) {
|
||||
const newDefault = hookFn(namespace, name, baseDir)
|
||||
if (newDefault && newDefault !== namespace) {
|
||||
// Only ESM modules that actually export `default` can have it reassigned.
|
||||
// Some hooks return a value unconditionally; avoid crashing when the module
|
||||
// has no default export (see issue #188).
|
||||
if ('default' in namespace) {
|
||||
namespace.default = newDefault
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sendModulesToLoader
|
||||
|
||||
/**
|
||||
* EXPERIMENTAL
|
||||
* This feature is experimental and may change in minor versions.
|
||||
* **NOTE** This feature is incompatible with the {internals: true} Hook option.
|
||||
*
|
||||
* Creates a message channel with a port that can be used to add hooks to the
|
||||
* list of exclusively included modules.
|
||||
*
|
||||
* This can be used to only wrap modules that are Hook'ed, however modules need
|
||||
* to be hooked before they are imported.
|
||||
*
|
||||
* ```ts
|
||||
* import { register } from 'module'
|
||||
* import { Hook, createAddHookMessageChannel } from 'import-in-the-middle'
|
||||
*
|
||||
* const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel()
|
||||
*
|
||||
* register('import-in-the-middle/hook.mjs', import.meta.url, registerOptions)
|
||||
*
|
||||
* Hook(['fs'], (exported, name, baseDir) => {
|
||||
* // Instrument the fs module
|
||||
* })
|
||||
*
|
||||
* // Ensure that the loader has acknowledged all the modules
|
||||
* // before we allow execution to continue
|
||||
* await waitForAllMessagesAcknowledged()
|
||||
* ```
|
||||
*/
|
||||
function createAddHookMessageChannel () {
|
||||
const { port1, port2 } = new MessageChannel()
|
||||
let pendingAckCount = 0
|
||||
let resolveFn
|
||||
|
||||
sendModulesToLoader = (modules) => {
|
||||
pendingAckCount++
|
||||
port1.postMessage(modules)
|
||||
}
|
||||
|
||||
port1.on('message', () => {
|
||||
pendingAckCount--
|
||||
|
||||
if (resolveFn && pendingAckCount <= 0) {
|
||||
resolveFn()
|
||||
}
|
||||
}).unref()
|
||||
|
||||
function waitForAllMessagesAcknowledged () {
|
||||
// This timer is to prevent the process from exiting with code 13:
|
||||
// 13: Unsettled Top-Level Await.
|
||||
const timer = setInterval(() => { }, 1000)
|
||||
const promise = new Promise((resolve) => {
|
||||
resolveFn = resolve
|
||||
}).then(() => { clearInterval(timer) })
|
||||
|
||||
if (pendingAckCount === 0) {
|
||||
resolveFn()
|
||||
}
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
const addHookMessagePort = port2
|
||||
const registerOptions = { data: { addHookMessagePort, include: [] }, transferList: [addHookMessagePort] }
|
||||
|
||||
return { registerOptions, addHookMessagePort, waitForAllMessagesAcknowledged }
|
||||
}
|
||||
|
||||
function Hook (modules, options, hookFn) {
|
||||
if ((this instanceof Hook) === false) return new Hook(modules, options, hookFn)
|
||||
if (typeof modules === 'function') {
|
||||
hookFn = modules
|
||||
modules = null
|
||||
options = null
|
||||
} else if (typeof options === 'function') {
|
||||
hookFn = options
|
||||
options = null
|
||||
}
|
||||
const internals = options ? options.internals === true : false
|
||||
|
||||
if (sendModulesToLoader && Array.isArray(modules)) {
|
||||
sendModulesToLoader(modules)
|
||||
}
|
||||
|
||||
this._iitmHook = (name, namespace, specifier) => {
|
||||
const loadUrl = name
|
||||
const isNodeUrl = loadUrl.startsWith('node:')
|
||||
let filePath, baseDir
|
||||
|
||||
if (isNodeUrl) {
|
||||
// Normalize builtin module name to *not* have 'node:' prefix, unless
|
||||
// required, as it is for 'node:test' and some others. `module.isBuiltin`
|
||||
// is available in all Node.js versions that have node:-only modules.
|
||||
const unprefixed = name.slice(5)
|
||||
if (isBuiltin(unprefixed)) {
|
||||
name = unprefixed
|
||||
}
|
||||
} else if (loadUrl.startsWith('file://')) {
|
||||
const stackTraceLimit = Error.stackTraceLimit
|
||||
Error.stackTraceLimit = 0
|
||||
try {
|
||||
filePath = fileURLToPath(name)
|
||||
name = filePath
|
||||
} catch (e) {}
|
||||
Error.stackTraceLimit = stackTraceLimit
|
||||
|
||||
if (filePath) {
|
||||
const details = moduleDetailsFromPath(filePath)
|
||||
if (details) {
|
||||
name = details.name
|
||||
baseDir = details.basedir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modules) {
|
||||
for (const matchArg of modules) {
|
||||
if (filePath && matchArg === filePath) {
|
||||
// abspath match
|
||||
callHookFn(hookFn, namespace, filePath, undefined)
|
||||
} else if (matchArg === name) {
|
||||
if (!baseDir) {
|
||||
// built-in module (or unexpected non file:// name?)
|
||||
callHookFn(hookFn, namespace, name, baseDir)
|
||||
} else if (baseDir.endsWith(specifiers.get(loadUrl))) {
|
||||
// An import of the top-level module (e.g. `import 'ioredis'`).
|
||||
// Note: Slight behaviour difference from RITM. RITM uses
|
||||
// `require.resolve(name)` to see if filename is the module
|
||||
// main file, which will catch `require('ioredis/built/index.js')`.
|
||||
// The check here will not catch `import 'ioredis/built/index.js'`.
|
||||
callHookFn(hookFn, namespace, name, baseDir)
|
||||
} else if (internals) {
|
||||
const internalPath = name + path.sep + path.relative(baseDir, filePath)
|
||||
callHookFn(hookFn, namespace, internalPath, baseDir)
|
||||
}
|
||||
} else if (matchArg === specifier) {
|
||||
callHookFn(hookFn, namespace, specifier, baseDir)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
callHookFn(hookFn, namespace, name, baseDir)
|
||||
}
|
||||
}
|
||||
|
||||
addHook(this._iitmHook)
|
||||
}
|
||||
|
||||
Hook.prototype.unhook = function () {
|
||||
removeHook(this._iitmHook)
|
||||
}
|
||||
|
||||
module.exports = Hook
|
||||
module.exports.Hook = Hook
|
||||
module.exports.addHook = addHook
|
||||
module.exports.removeHook = removeHook
|
||||
module.exports.createAddHookMessageChannel = createAddHookMessageChannel
|
||||
Generated
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2.0 License.
|
||||
//
|
||||
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2021 Datadog, Inc.
|
||||
|
||||
const importHooks = [] // TODO should this be a Set?
|
||||
const setters = new WeakMap()
|
||||
const getters = new WeakMap()
|
||||
const specifiers = new Map()
|
||||
const toHook = []
|
||||
|
||||
const proxyHandler = {
|
||||
set (target, name, value) {
|
||||
const set = setters.get(target)
|
||||
const setter = set && set[name]
|
||||
if (typeof setter === 'function') {
|
||||
return setter(value)
|
||||
}
|
||||
// If a module doesn't export the property being assigned (e.g. no default
|
||||
// export), there is no setter to call. Don't crash userland code.
|
||||
return true
|
||||
},
|
||||
|
||||
get (target, name) {
|
||||
if (name === Symbol.toStringTag) {
|
||||
return 'Module'
|
||||
}
|
||||
|
||||
const getter = getters.get(target)[name]
|
||||
|
||||
if (typeof getter === 'function') {
|
||||
return getter()
|
||||
}
|
||||
},
|
||||
|
||||
defineProperty (target, property, descriptor) {
|
||||
if ((!('value' in descriptor))) {
|
||||
throw new Error('Getters/setters are not supported for exports property descriptors.')
|
||||
}
|
||||
|
||||
const set = setters.get(target)
|
||||
const setter = set && set[property]
|
||||
if (typeof setter === 'function') {
|
||||
return setter(descriptor.value)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
function register (name, namespace, set, get, specifier) {
|
||||
specifiers.set(name, specifier)
|
||||
setters.set(namespace, set)
|
||||
getters.set(namespace, get)
|
||||
const proxy = new Proxy(namespace, proxyHandler)
|
||||
importHooks.forEach(hook => hook(name, proxy, specifier))
|
||||
toHook.push([name, proxy, specifier])
|
||||
}
|
||||
|
||||
exports.register = register
|
||||
exports.importHooks = importHooks
|
||||
exports.specifiers = specifiers
|
||||
exports.toHook = toHook
|
||||
Generated
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "import-in-the-middle",
|
||||
"version": "2.0.6",
|
||||
"description": "Intercept imports in Node.js",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "c8 --reporter lcov --check-coverage --lines 45 imhotap --files test/{hook,low-level,other,get-esm-exports,register}/*",
|
||||
"test:e2e": "node test/check-exports/test.mjs",
|
||||
"test:ts": "c8 --reporter lcov imhotap --files test/typescript/*.test.mts",
|
||||
"coverage": "c8 --reporter html imhotap --files test/{hook,low-level,other,get-esm-exports,register}/* && echo \"\nNow open coverage/index.html\n\"",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+ssh://git@github.com/nodejs/import-in-the-middle.git"
|
||||
},
|
||||
"keywords": [
|
||||
"import",
|
||||
"ritm",
|
||||
"iitm",
|
||||
"loader",
|
||||
"hook",
|
||||
"hooks"
|
||||
],
|
||||
"author": "Bryan English <bryan.english@datadoghq.com>",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nodejs/import-in-the-middle/issues"
|
||||
},
|
||||
"homepage": "https://github.com/nodejs/import-in-the-middle#readme",
|
||||
"imhotap": {
|
||||
"runner": "node",
|
||||
"test-env": "NODE_OPTIONS=--no-warnings --require ./test/version-check.js --experimental-loader ./test/generic-loader.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/eslint-parser": "^7.28.5",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.27.1",
|
||||
"@node-rs/crc32": "^1.10.6",
|
||||
"@react-email/components": "^0.0.19",
|
||||
"@types/node": "^18.0.6",
|
||||
"c8": "^7.14.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-standard": "^17.1.0",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-n": "^16.6.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^6.6.0",
|
||||
"got": "^14.6.6",
|
||||
"imhotap": "^2.2.0",
|
||||
"openai": "4.47.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^4.9.5",
|
||||
"vue": "^3.5.26"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"cjs-module-lexer": "^2.2.0",
|
||||
"module-details-from-path": "^1.0.4"
|
||||
}
|
||||
}
|
||||
.next/standalone/node_modules/.pnpm/import-in-the-middle@2.0.6/node_modules/module-details-from-path
Generated
Vendored
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../module-details-from-path@1.0.4/node_modules/module-details-from-path
|
||||
Reference in New Issue
Block a user