@cedarjs/internal 6.0.0-canary.2615 → 6.0.0-canary.2620
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/dist/build/api.d.ts.map +1 -1
- package/dist/build/api.js +7 -3
- package/dist/build/esbuild-plugin-api-graphql.d.ts.map +1 -1
- package/dist/build/esbuild-plugin-api-graphql.js +5 -2
- package/dist/build/esbuild-plugin-cedar-otel-wrapping.d.ts +13 -0
- package/dist/build/esbuild-plugin-cedar-otel-wrapping.d.ts.map +1 -0
- package/dist/build/esbuild-plugin-cedar-otel-wrapping.js +180 -0
- package/dist/build/esbuild-plugin-handler-als-wrapping.js +10 -10
- package/dist/cjs/build/api.d.ts.map +1 -1
- package/dist/cjs/build/api.js +7 -3
- package/dist/cjs/build/esbuild-plugin-api-graphql.d.ts.map +1 -1
- package/dist/cjs/build/esbuild-plugin-api-graphql.js +4 -1
- package/dist/cjs/build/esbuild-plugin-cedar-otel-wrapping.d.ts +13 -0
- package/dist/cjs/build/esbuild-plugin-cedar-otel-wrapping.d.ts.map +1 -0
- package/dist/cjs/build/esbuild-plugin-cedar-otel-wrapping.js +214 -0
- package/dist/cjs/build/esbuild-plugin-handler-als-wrapping.js +10 -10
- package/package.json +9 -9
package/dist/build/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/build/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,YAAY,EAAe,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/build/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,YAAY,EAAe,MAAM,SAAS,CAAA;AAuBtE,eAAO,MAAM,QAAQ,4DAIpB,CAAA;AAED,eAAO,MAAM,UAAU,4DAStB,CAAA;AAED,eAAO,MAAM,aAAa,qBAGzB,CAAA;AAuID,eAAO,MAAM,gBAAgB,iHAqD5B,CAAA;AAcD,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
package/dist/build/api.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
applyGraphqlOptionsExtract
|
|
14
14
|
} from "./api-graphql-transforms.js";
|
|
15
15
|
import { cedarApiGraphqlPlugin } from "./esbuild-plugin-api-graphql.js";
|
|
16
|
+
import { applyOtelWrapping } from "./esbuild-plugin-cedar-otel-wrapping.js";
|
|
16
17
|
import { applyHandlerAlsWrapping } from "./esbuild-plugin-handler-als-wrapping.js";
|
|
17
18
|
let BUILD_CTX = null;
|
|
18
19
|
const buildApi = async () => {
|
|
@@ -37,14 +38,12 @@ const cleanApiBuild = async () => {
|
|
|
37
38
|
const runCedarBabelTransformsPlugin = {
|
|
38
39
|
name: "cedar-esbuild-babel-transform",
|
|
39
40
|
setup(build2) {
|
|
40
|
-
const cedarConfig = getConfig();
|
|
41
41
|
build2.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, async (args) => {
|
|
42
42
|
const fileContents = await fs.promises.readFile(args.path, "utf-8");
|
|
43
43
|
const transformedCode = await transformWithBabel(
|
|
44
44
|
fileContents,
|
|
45
45
|
args.path,
|
|
46
46
|
getApiSideBabelPlugins({
|
|
47
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
48
47
|
projectIsEsm: projectSideIsEsm("api")
|
|
49
48
|
})
|
|
50
49
|
);
|
|
@@ -59,6 +58,9 @@ const runCedarBabelTransformsPlugin = {
|
|
|
59
58
|
projectIsEsm: isEsm
|
|
60
59
|
}) ?? code;
|
|
61
60
|
}
|
|
61
|
+
if (normalizedPath.startsWith(normalizePath(cedarPaths.api.src) + "/")) {
|
|
62
|
+
code = applyOtelWrapping(code, args.path, cedarPaths.api.src) ?? code;
|
|
63
|
+
}
|
|
62
64
|
return {
|
|
63
65
|
contents: code,
|
|
64
66
|
loader: "js"
|
|
@@ -95,13 +97,15 @@ function createCedarViteApiPlugin() {
|
|
|
95
97
|
sourceCode,
|
|
96
98
|
id,
|
|
97
99
|
getApiSideBabelPlugins({
|
|
98
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
99
100
|
projectIsEsm: isEsm
|
|
100
101
|
}),
|
|
101
102
|
true
|
|
102
103
|
);
|
|
103
104
|
if (transformedCode?.code) {
|
|
104
105
|
let code2 = transformedCode.code;
|
|
106
|
+
if (cedarConfig.experimental?.opentelemetry?.enabled && cedarConfig.experimental?.opentelemetry?.wrapApi) {
|
|
107
|
+
code2 = applyOtelWrapping(code2, id, cedarPaths.api.src) ?? code2;
|
|
108
|
+
}
|
|
105
109
|
const functionsDir = normalizePath(cedarPaths.api.functions);
|
|
106
110
|
if (normalizedId.startsWith(functionsDir + "/")) {
|
|
107
111
|
code2 = applyHandlerAlsWrapping(code2, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esbuild-plugin-api-graphql.d.ts","sourceRoot":"","sources":["../../src/build/esbuild-plugin-api-graphql.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"esbuild-plugin-api-graphql.d.ts","sourceRoot":"","sources":["../../src/build/esbuild-plugin-api-graphql.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAe1C,eAAO,MAAM,qBAAqB;;iBAEnB,WAAW;CA0DzB,CAAA"}
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
getApiSideBabelPlugins,
|
|
4
4
|
transformWithBabel
|
|
5
5
|
} from "@cedarjs/babel-config";
|
|
6
|
-
import { getConfig, projectSideIsEsm } from "@cedarjs/project-config";
|
|
6
|
+
import { getConfig, getPaths, projectSideIsEsm } from "@cedarjs/project-config";
|
|
7
7
|
import {
|
|
8
8
|
applyGqlormInject,
|
|
9
9
|
applyGraphqlOptionsExtract
|
|
10
10
|
} from "./api-graphql-transforms.js";
|
|
11
|
+
import { applyOtelWrapping } from "./esbuild-plugin-cedar-otel-wrapping.js";
|
|
11
12
|
import { applyHandlerAlsWrapping } from "./esbuild-plugin-handler-als-wrapping.js";
|
|
12
13
|
const cedarApiGraphqlPlugin = {
|
|
13
14
|
name: "cedar-api-graphql",
|
|
@@ -21,7 +22,6 @@ const cedarApiGraphqlPlugin = {
|
|
|
21
22
|
fileContents,
|
|
22
23
|
args.path,
|
|
23
24
|
getApiSideBabelPlugins({
|
|
24
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
25
25
|
projectIsEsm: projectSideIsEsm("api")
|
|
26
26
|
})
|
|
27
27
|
);
|
|
@@ -29,6 +29,9 @@ const cedarApiGraphqlPlugin = {
|
|
|
29
29
|
throw new Error(`Could not transform file: ${args.path}`);
|
|
30
30
|
}
|
|
31
31
|
let code = transformedCode.code;
|
|
32
|
+
if (cedarConfig.experimental?.opentelemetry?.enabled && cedarConfig.experimental?.opentelemetry?.wrapApi) {
|
|
33
|
+
code = applyOtelWrapping(code, args.path, getPaths().api.src) ?? code;
|
|
34
|
+
}
|
|
32
35
|
code = applyHandlerAlsWrapping(code, {
|
|
33
36
|
projectIsEsm: projectSideIsEsm("api")
|
|
34
37
|
}) ?? code;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone esbuild equivalent of the Vite cedarOtelWrappingPlugin. Applied
|
|
3
|
+
* inline in the esbuild API build and the standalone-Vite API build so neither
|
|
4
|
+
* path depends on a Babel OTel plugin.
|
|
5
|
+
*
|
|
6
|
+
* For each `export const fn = (async?) (...) => {...}` in an API file, this
|
|
7
|
+
* wraps it with an OpenTelemetry span.
|
|
8
|
+
*
|
|
9
|
+
* Keep this in sync with
|
|
10
|
+
* packages/vite/src/plugins/vite-plugin-cedar-otel-wrapping.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyOtelWrapping(code: string, filename: string, apiSrc: string): string | null;
|
|
13
|
+
//# sourceMappingURL=esbuild-plugin-cedar-otel-wrapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"esbuild-plugin-cedar-otel-wrapping.d.ts","sourceRoot":"","sources":["../../src/build/esbuild-plugin-cedar-otel-wrapping.ts"],"names":[],"mappings":"AASA;;;;;;;;;;GAUG;AAEH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAmFf"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { parseSync } from "oxc-parser";
|
|
3
|
+
function applyOtelWrapping(code, filename, apiSrc) {
|
|
4
|
+
const relative = path.relative(apiSrc, filename);
|
|
5
|
+
const apiFolder = relative.split(path.sep)[0] ?? "?";
|
|
6
|
+
const parseResult = parseSync(filename, code, { sourceType: "module" });
|
|
7
|
+
const replacements = [];
|
|
8
|
+
for (const node of parseResult.program.body) {
|
|
9
|
+
if (node.type !== "ExportNamedDeclaration") {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const decl = node.declaration;
|
|
13
|
+
if (decl?.type !== "VariableDeclaration") {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const declarator = decl.declarations[0];
|
|
17
|
+
if (!declarator) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
const fn = declarator.init;
|
|
21
|
+
if (fn?.type !== "ArrowFunctionExpression") {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (declarator.id.type !== "Identifier") {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const fnName = declarator.id.name;
|
|
28
|
+
const innerArgs = buildInnerArgs(fn.params);
|
|
29
|
+
if (innerArgs === null) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const fnHeader = code.slice(fn.start, fn.body.start);
|
|
33
|
+
const originalFnSrc = code.slice(fn.start, fn.end);
|
|
34
|
+
const isAsync = fn.async;
|
|
35
|
+
const awaitKw = isAsync ? "await " : "";
|
|
36
|
+
const asyncKw = isAsync ? "async " : "";
|
|
37
|
+
replacements.push({
|
|
38
|
+
start: node.start,
|
|
39
|
+
end: node.end,
|
|
40
|
+
src: buildWrappedExport(
|
|
41
|
+
fnName,
|
|
42
|
+
fnHeader,
|
|
43
|
+
originalFnSrc,
|
|
44
|
+
innerArgs,
|
|
45
|
+
awaitKw,
|
|
46
|
+
asyncKw,
|
|
47
|
+
apiFolder,
|
|
48
|
+
filename
|
|
49
|
+
)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (replacements.length === 0) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
let output = code;
|
|
56
|
+
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
57
|
+
const r = replacements[i];
|
|
58
|
+
output = output.slice(0, r.start) + r.src + output.slice(r.end);
|
|
59
|
+
}
|
|
60
|
+
return `import { trace as OTEL_TRACE } from '@opentelemetry/api'
|
|
61
|
+
` + output;
|
|
62
|
+
}
|
|
63
|
+
function buildInnerArgs(params) {
|
|
64
|
+
const args = [];
|
|
65
|
+
for (const param of params) {
|
|
66
|
+
if (param.type === "RestElement" || param.type === "ArrayPattern" || param.type === "TSParameterProperty") {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (param.type === "Identifier") {
|
|
70
|
+
args.push(param.name);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (param.type === "ObjectPattern") {
|
|
74
|
+
for (const prop of param.properties) {
|
|
75
|
+
if (prop.type === "RestElement") {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (prop.key.type !== "Identifier") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const value = prop.value;
|
|
82
|
+
if (value.type !== "Identifier" && value.type !== "AssignmentPattern" && value.type !== "ObjectPattern") {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (value.type === "AssignmentPattern") {
|
|
86
|
+
if (value.left.type !== "Identifier" && value.left.type !== "ObjectPattern") {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const obj = buildObjectCallArg(param);
|
|
92
|
+
if (obj === null) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
args.push(obj);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (param.type === "AssignmentPattern") {
|
|
99
|
+
const ap = param;
|
|
100
|
+
if (ap.left.type === "Identifier") {
|
|
101
|
+
args.push(ap.left.name);
|
|
102
|
+
} else if (ap.left.type === "ObjectPattern") {
|
|
103
|
+
const obj = buildObjectCallArg(ap.left);
|
|
104
|
+
if (obj === null) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
args.push(obj);
|
|
108
|
+
} else {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return args.join(", ");
|
|
116
|
+
}
|
|
117
|
+
function buildObjectCallArg(pattern) {
|
|
118
|
+
const keys = [];
|
|
119
|
+
for (const prop of pattern.properties) {
|
|
120
|
+
if (prop.type === "RestElement") {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
if (prop.key.type !== "Identifier") {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const keyName = prop.key.name;
|
|
127
|
+
let valueName = null;
|
|
128
|
+
if (prop.value.type === "Identifier") {
|
|
129
|
+
valueName = prop.value.name;
|
|
130
|
+
} else if (prop.value.type === "AssignmentPattern") {
|
|
131
|
+
if (prop.value.left.type === "Identifier") {
|
|
132
|
+
valueName = prop.value.left.name;
|
|
133
|
+
} else {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
if (valueName !== keyName) {
|
|
140
|
+
keys.push(`${keyName}: ${valueName}`);
|
|
141
|
+
} else {
|
|
142
|
+
keys.push(keyName);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return `{ ${keys.join(", ")} }`;
|
|
146
|
+
}
|
|
147
|
+
function buildWrappedExport(fnName, fnHeader, originalFnSrc, innerArgs, awaitKw, asyncKw, apiFolder, filename) {
|
|
148
|
+
const privateName = `__${fnName}`;
|
|
149
|
+
const spanName = `redwoodjs:api:${apiFolder}:${fnName}`;
|
|
150
|
+
return `export const ${fnName} = ${fnHeader}{
|
|
151
|
+
const ${privateName} = ${originalFnSrc}
|
|
152
|
+
const OTEL_TRACER = OTEL_TRACE.getTracer('redwoodjs')
|
|
153
|
+
const OTEL_RESULT = ${awaitKw}OTEL_TRACER.startActiveSpan(
|
|
154
|
+
'${spanName}',
|
|
155
|
+
${asyncKw}(span) => {
|
|
156
|
+
span.setAttribute('code.function', '${fnName}')
|
|
157
|
+
span.setAttribute('code.filepath', ${JSON.stringify(filename)})
|
|
158
|
+
try {
|
|
159
|
+
const OTEL_INNER_RESULT = ${awaitKw}${privateName}(${innerArgs})
|
|
160
|
+
span.end()
|
|
161
|
+
return OTEL_INNER_RESULT
|
|
162
|
+
} catch (error) {
|
|
163
|
+
span.recordException(error)
|
|
164
|
+
span.setStatus({
|
|
165
|
+
code: 2,
|
|
166
|
+
message:
|
|
167
|
+
error?.message?.split('\\n')[0] ??
|
|
168
|
+
error?.toString()?.split('\\n')[0],
|
|
169
|
+
})
|
|
170
|
+
span.end()
|
|
171
|
+
throw error
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
return OTEL_RESULT
|
|
176
|
+
}`;
|
|
177
|
+
}
|
|
178
|
+
export {
|
|
179
|
+
applyOtelWrapping
|
|
180
|
+
};
|
|
@@ -7,25 +7,25 @@ function applyHandlerAlsWrapping(code, { projectIsEsm = false } = {}) {
|
|
|
7
7
|
const afterEquals = code.slice(handlerMatch.index + handlerMatch[0].length).trimStart();
|
|
8
8
|
const isAsync = /^async(?:\s*[\(\*]|\s+function)/.test(afterEquals);
|
|
9
9
|
const storePath = projectIsEsm ? "@cedarjs/context/dist/store.js" : "@cedarjs/context/dist/store";
|
|
10
|
-
const importStatement = `import { getAsyncStoreInstance as
|
|
10
|
+
const importStatement = `import { getAsyncStoreInstance as __cedar_getAsyncStoreInstance } from '${storePath}'
|
|
11
11
|
`;
|
|
12
12
|
const handlerStart = handlerMatch.index;
|
|
13
13
|
const before = code.slice(0, handlerStart);
|
|
14
14
|
const after = code.slice(handlerStart);
|
|
15
|
-
const renamed = after.replace(handlerRe, "const
|
|
15
|
+
const renamed = after.replace(handlerRe, "const __cedar_handler =");
|
|
16
16
|
const wrappedHandler = `
|
|
17
|
-
export const handler = ${isAsync ? "async " : ""}(
|
|
17
|
+
export const handler = ${isAsync ? "async " : ""}(__cedar_event, __cedar_context) => {
|
|
18
18
|
// The store will be undefined if no context isolation has been performed yet
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
21
|
-
return
|
|
19
|
+
const __cedar_contextStore = __cedar_getAsyncStoreInstance().getStore()
|
|
20
|
+
if (__cedar_contextStore === undefined) {
|
|
21
|
+
return __cedar_getAsyncStoreInstance().run(
|
|
22
22
|
new Map(),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
__cedar_handler,
|
|
24
|
+
__cedar_event,
|
|
25
|
+
__cedar_context
|
|
26
26
|
)
|
|
27
27
|
}
|
|
28
|
-
return
|
|
28
|
+
return __cedar_handler(__cedar_event, __cedar_context)
|
|
29
29
|
}
|
|
30
30
|
`;
|
|
31
31
|
return before + importStatement + renamed + wrappedHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/build/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,YAAY,EAAe,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/build/api.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,YAAY,EAAe,MAAM,SAAS,CAAA;AAuBtE,eAAO,MAAM,QAAQ,4DAIpB,CAAA;AAED,eAAO,MAAM,UAAU,4DAStB,CAAA;AAED,eAAO,MAAM,aAAa,qBAGzB,CAAA;AAuID,eAAO,MAAM,gBAAgB,iHAqD5B,CAAA;AAcD,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAoDf"}
|
package/dist/cjs/build/api.js
CHANGED
|
@@ -44,6 +44,7 @@ var import_project_config = require("@cedarjs/project-config");
|
|
|
44
44
|
var import_files = require("../files.js");
|
|
45
45
|
var import_api_graphql_transforms = require("./api-graphql-transforms.js");
|
|
46
46
|
var import_esbuild_plugin_api_graphql = require("./esbuild-plugin-api-graphql.js");
|
|
47
|
+
var import_esbuild_plugin_cedar_otel_wrapping = require("./esbuild-plugin-cedar-otel-wrapping.js");
|
|
47
48
|
var import_esbuild_plugin_handler_als_wrapping = require("./esbuild-plugin-handler-als-wrapping.js");
|
|
48
49
|
let BUILD_CTX = null;
|
|
49
50
|
const buildApi = async () => {
|
|
@@ -68,14 +69,12 @@ const cleanApiBuild = async () => {
|
|
|
68
69
|
const runCedarBabelTransformsPlugin = {
|
|
69
70
|
name: "cedar-esbuild-babel-transform",
|
|
70
71
|
setup(build2) {
|
|
71
|
-
const cedarConfig = (0, import_project_config.getConfig)();
|
|
72
72
|
build2.onLoad({ filter: /\.(js|ts|tsx|jsx)$/ }, async (args) => {
|
|
73
73
|
const fileContents = await import_node_fs.default.promises.readFile(args.path, "utf-8");
|
|
74
74
|
const transformedCode = await (0, import_babel_config.transformWithBabel)(
|
|
75
75
|
fileContents,
|
|
76
76
|
args.path,
|
|
77
77
|
(0, import_babel_config.getApiSideBabelPlugins)({
|
|
78
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
79
78
|
projectIsEsm: (0, import_project_config.projectSideIsEsm)("api")
|
|
80
79
|
})
|
|
81
80
|
);
|
|
@@ -90,6 +89,9 @@ const runCedarBabelTransformsPlugin = {
|
|
|
90
89
|
projectIsEsm: isEsm
|
|
91
90
|
}) ?? code;
|
|
92
91
|
}
|
|
92
|
+
if (normalizedPath.startsWith((0, import_vite.normalizePath)(cedarPaths.api.src) + "/")) {
|
|
93
|
+
code = (0, import_esbuild_plugin_cedar_otel_wrapping.applyOtelWrapping)(code, args.path, cedarPaths.api.src) ?? code;
|
|
94
|
+
}
|
|
93
95
|
return {
|
|
94
96
|
contents: code,
|
|
95
97
|
loader: "js"
|
|
@@ -126,13 +128,15 @@ function createCedarViteApiPlugin() {
|
|
|
126
128
|
sourceCode,
|
|
127
129
|
id,
|
|
128
130
|
(0, import_babel_config.getApiSideBabelPlugins)({
|
|
129
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
130
131
|
projectIsEsm: isEsm
|
|
131
132
|
}),
|
|
132
133
|
true
|
|
133
134
|
);
|
|
134
135
|
if (transformedCode?.code) {
|
|
135
136
|
let code2 = transformedCode.code;
|
|
137
|
+
if (cedarConfig.experimental?.opentelemetry?.enabled && cedarConfig.experimental?.opentelemetry?.wrapApi) {
|
|
138
|
+
code2 = (0, import_esbuild_plugin_cedar_otel_wrapping.applyOtelWrapping)(code2, id, cedarPaths.api.src) ?? code2;
|
|
139
|
+
}
|
|
136
140
|
const functionsDir = (0, import_vite.normalizePath)(cedarPaths.api.functions);
|
|
137
141
|
if (normalizedId.startsWith(functionsDir + "/")) {
|
|
138
142
|
code2 = (0, import_esbuild_plugin_handler_als_wrapping.applyHandlerAlsWrapping)(code2, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esbuild-plugin-api-graphql.d.ts","sourceRoot":"","sources":["../../../src/build/esbuild-plugin-api-graphql.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"esbuild-plugin-api-graphql.d.ts","sourceRoot":"","sources":["../../../src/build/esbuild-plugin-api-graphql.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAe1C,eAAO,MAAM,qBAAqB;;iBAEnB,WAAW;CA0DzB,CAAA"}
|
|
@@ -35,6 +35,7 @@ var import_node_fs = __toESM(require("node:fs"), 1);
|
|
|
35
35
|
var import_babel_config = require("@cedarjs/babel-config");
|
|
36
36
|
var import_project_config = require("@cedarjs/project-config");
|
|
37
37
|
var import_api_graphql_transforms = require("./api-graphql-transforms.js");
|
|
38
|
+
var import_esbuild_plugin_cedar_otel_wrapping = require("./esbuild-plugin-cedar-otel-wrapping.js");
|
|
38
39
|
var import_esbuild_plugin_handler_als_wrapping = require("./esbuild-plugin-handler-als-wrapping.js");
|
|
39
40
|
const cedarApiGraphqlPlugin = {
|
|
40
41
|
name: "cedar-api-graphql",
|
|
@@ -48,7 +49,6 @@ const cedarApiGraphqlPlugin = {
|
|
|
48
49
|
fileContents,
|
|
49
50
|
args.path,
|
|
50
51
|
(0, import_babel_config.getApiSideBabelPlugins)({
|
|
51
|
-
openTelemetry: cedarConfig.experimental.opentelemetry.enabled && cedarConfig.experimental.opentelemetry.wrapApi,
|
|
52
52
|
projectIsEsm: (0, import_project_config.projectSideIsEsm)("api")
|
|
53
53
|
})
|
|
54
54
|
);
|
|
@@ -56,6 +56,9 @@ const cedarApiGraphqlPlugin = {
|
|
|
56
56
|
throw new Error(`Could not transform file: ${args.path}`);
|
|
57
57
|
}
|
|
58
58
|
let code = transformedCode.code;
|
|
59
|
+
if (cedarConfig.experimental?.opentelemetry?.enabled && cedarConfig.experimental?.opentelemetry?.wrapApi) {
|
|
60
|
+
code = (0, import_esbuild_plugin_cedar_otel_wrapping.applyOtelWrapping)(code, args.path, (0, import_project_config.getPaths)().api.src) ?? code;
|
|
61
|
+
}
|
|
59
62
|
code = (0, import_esbuild_plugin_handler_als_wrapping.applyHandlerAlsWrapping)(code, {
|
|
60
63
|
projectIsEsm: (0, import_project_config.projectSideIsEsm)("api")
|
|
61
64
|
}) ?? code;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone esbuild equivalent of the Vite cedarOtelWrappingPlugin. Applied
|
|
3
|
+
* inline in the esbuild API build and the standalone-Vite API build so neither
|
|
4
|
+
* path depends on a Babel OTel plugin.
|
|
5
|
+
*
|
|
6
|
+
* For each `export const fn = (async?) (...) => {...}` in an API file, this
|
|
7
|
+
* wraps it with an OpenTelemetry span.
|
|
8
|
+
*
|
|
9
|
+
* Keep this in sync with
|
|
10
|
+
* packages/vite/src/plugins/vite-plugin-cedar-otel-wrapping.ts.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyOtelWrapping(code: string, filename: string, apiSrc: string): string | null;
|
|
13
|
+
//# sourceMappingURL=esbuild-plugin-cedar-otel-wrapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"esbuild-plugin-cedar-otel-wrapping.d.ts","sourceRoot":"","sources":["../../../src/build/esbuild-plugin-cedar-otel-wrapping.ts"],"names":[],"mappings":"AASA;;;;;;;;;;GAUG;AAEH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,IAAI,CAmFf"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var esbuild_plugin_cedar_otel_wrapping_exports = {};
|
|
30
|
+
__export(esbuild_plugin_cedar_otel_wrapping_exports, {
|
|
31
|
+
applyOtelWrapping: () => applyOtelWrapping
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(esbuild_plugin_cedar_otel_wrapping_exports);
|
|
34
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
35
|
+
var import_oxc_parser = require("oxc-parser");
|
|
36
|
+
function applyOtelWrapping(code, filename, apiSrc) {
|
|
37
|
+
const relative = import_node_path.default.relative(apiSrc, filename);
|
|
38
|
+
const apiFolder = relative.split(import_node_path.default.sep)[0] ?? "?";
|
|
39
|
+
const parseResult = (0, import_oxc_parser.parseSync)(filename, code, { sourceType: "module" });
|
|
40
|
+
const replacements = [];
|
|
41
|
+
for (const node of parseResult.program.body) {
|
|
42
|
+
if (node.type !== "ExportNamedDeclaration") {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const decl = node.declaration;
|
|
46
|
+
if (decl?.type !== "VariableDeclaration") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const declarator = decl.declarations[0];
|
|
50
|
+
if (!declarator) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const fn = declarator.init;
|
|
54
|
+
if (fn?.type !== "ArrowFunctionExpression") {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (declarator.id.type !== "Identifier") {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const fnName = declarator.id.name;
|
|
61
|
+
const innerArgs = buildInnerArgs(fn.params);
|
|
62
|
+
if (innerArgs === null) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const fnHeader = code.slice(fn.start, fn.body.start);
|
|
66
|
+
const originalFnSrc = code.slice(fn.start, fn.end);
|
|
67
|
+
const isAsync = fn.async;
|
|
68
|
+
const awaitKw = isAsync ? "await " : "";
|
|
69
|
+
const asyncKw = isAsync ? "async " : "";
|
|
70
|
+
replacements.push({
|
|
71
|
+
start: node.start,
|
|
72
|
+
end: node.end,
|
|
73
|
+
src: buildWrappedExport(
|
|
74
|
+
fnName,
|
|
75
|
+
fnHeader,
|
|
76
|
+
originalFnSrc,
|
|
77
|
+
innerArgs,
|
|
78
|
+
awaitKw,
|
|
79
|
+
asyncKw,
|
|
80
|
+
apiFolder,
|
|
81
|
+
filename
|
|
82
|
+
)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (replacements.length === 0) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
let output = code;
|
|
89
|
+
for (let i = replacements.length - 1; i >= 0; i--) {
|
|
90
|
+
const r = replacements[i];
|
|
91
|
+
output = output.slice(0, r.start) + r.src + output.slice(r.end);
|
|
92
|
+
}
|
|
93
|
+
return `import { trace as OTEL_TRACE } from '@opentelemetry/api'
|
|
94
|
+
` + output;
|
|
95
|
+
}
|
|
96
|
+
function buildInnerArgs(params) {
|
|
97
|
+
const args = [];
|
|
98
|
+
for (const param of params) {
|
|
99
|
+
if (param.type === "RestElement" || param.type === "ArrayPattern" || param.type === "TSParameterProperty") {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
if (param.type === "Identifier") {
|
|
103
|
+
args.push(param.name);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (param.type === "ObjectPattern") {
|
|
107
|
+
for (const prop of param.properties) {
|
|
108
|
+
if (prop.type === "RestElement") {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
if (prop.key.type !== "Identifier") {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const value = prop.value;
|
|
115
|
+
if (value.type !== "Identifier" && value.type !== "AssignmentPattern" && value.type !== "ObjectPattern") {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
if (value.type === "AssignmentPattern") {
|
|
119
|
+
if (value.left.type !== "Identifier" && value.left.type !== "ObjectPattern") {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const obj = buildObjectCallArg(param);
|
|
125
|
+
if (obj === null) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
args.push(obj);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (param.type === "AssignmentPattern") {
|
|
132
|
+
const ap = param;
|
|
133
|
+
if (ap.left.type === "Identifier") {
|
|
134
|
+
args.push(ap.left.name);
|
|
135
|
+
} else if (ap.left.type === "ObjectPattern") {
|
|
136
|
+
const obj = buildObjectCallArg(ap.left);
|
|
137
|
+
if (obj === null) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
args.push(obj);
|
|
141
|
+
} else {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
return args.join(", ");
|
|
149
|
+
}
|
|
150
|
+
function buildObjectCallArg(pattern) {
|
|
151
|
+
const keys = [];
|
|
152
|
+
for (const prop of pattern.properties) {
|
|
153
|
+
if (prop.type === "RestElement") {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
if (prop.key.type !== "Identifier") {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
const keyName = prop.key.name;
|
|
160
|
+
let valueName = null;
|
|
161
|
+
if (prop.value.type === "Identifier") {
|
|
162
|
+
valueName = prop.value.name;
|
|
163
|
+
} else if (prop.value.type === "AssignmentPattern") {
|
|
164
|
+
if (prop.value.left.type === "Identifier") {
|
|
165
|
+
valueName = prop.value.left.name;
|
|
166
|
+
} else {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
if (valueName !== keyName) {
|
|
173
|
+
keys.push(`${keyName}: ${valueName}`);
|
|
174
|
+
} else {
|
|
175
|
+
keys.push(keyName);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return `{ ${keys.join(", ")} }`;
|
|
179
|
+
}
|
|
180
|
+
function buildWrappedExport(fnName, fnHeader, originalFnSrc, innerArgs, awaitKw, asyncKw, apiFolder, filename) {
|
|
181
|
+
const privateName = `__${fnName}`;
|
|
182
|
+
const spanName = `redwoodjs:api:${apiFolder}:${fnName}`;
|
|
183
|
+
return `export const ${fnName} = ${fnHeader}{
|
|
184
|
+
const ${privateName} = ${originalFnSrc}
|
|
185
|
+
const OTEL_TRACER = OTEL_TRACE.getTracer('redwoodjs')
|
|
186
|
+
const OTEL_RESULT = ${awaitKw}OTEL_TRACER.startActiveSpan(
|
|
187
|
+
'${spanName}',
|
|
188
|
+
${asyncKw}(span) => {
|
|
189
|
+
span.setAttribute('code.function', '${fnName}')
|
|
190
|
+
span.setAttribute('code.filepath', ${JSON.stringify(filename)})
|
|
191
|
+
try {
|
|
192
|
+
const OTEL_INNER_RESULT = ${awaitKw}${privateName}(${innerArgs})
|
|
193
|
+
span.end()
|
|
194
|
+
return OTEL_INNER_RESULT
|
|
195
|
+
} catch (error) {
|
|
196
|
+
span.recordException(error)
|
|
197
|
+
span.setStatus({
|
|
198
|
+
code: 2,
|
|
199
|
+
message:
|
|
200
|
+
error?.message?.split('\\n')[0] ??
|
|
201
|
+
error?.toString()?.split('\\n')[0],
|
|
202
|
+
})
|
|
203
|
+
span.end()
|
|
204
|
+
throw error
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
return OTEL_RESULT
|
|
209
|
+
}`;
|
|
210
|
+
}
|
|
211
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
212
|
+
0 && (module.exports = {
|
|
213
|
+
applyOtelWrapping
|
|
214
|
+
});
|
|
@@ -30,25 +30,25 @@ function applyHandlerAlsWrapping(code, { projectIsEsm = false } = {}) {
|
|
|
30
30
|
const afterEquals = code.slice(handlerMatch.index + handlerMatch[0].length).trimStart();
|
|
31
31
|
const isAsync = /^async(?:\s*[\(\*]|\s+function)/.test(afterEquals);
|
|
32
32
|
const storePath = projectIsEsm ? "@cedarjs/context/dist/store.js" : "@cedarjs/context/dist/store";
|
|
33
|
-
const importStatement = `import { getAsyncStoreInstance as
|
|
33
|
+
const importStatement = `import { getAsyncStoreInstance as __cedar_getAsyncStoreInstance } from '${storePath}'
|
|
34
34
|
`;
|
|
35
35
|
const handlerStart = handlerMatch.index;
|
|
36
36
|
const before = code.slice(0, handlerStart);
|
|
37
37
|
const after = code.slice(handlerStart);
|
|
38
|
-
const renamed = after.replace(handlerRe, "const
|
|
38
|
+
const renamed = after.replace(handlerRe, "const __cedar_handler =");
|
|
39
39
|
const wrappedHandler = `
|
|
40
|
-
export const handler = ${isAsync ? "async " : ""}(
|
|
40
|
+
export const handler = ${isAsync ? "async " : ""}(__cedar_event, __cedar_context) => {
|
|
41
41
|
// The store will be undefined if no context isolation has been performed yet
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
42
|
+
const __cedar_contextStore = __cedar_getAsyncStoreInstance().getStore()
|
|
43
|
+
if (__cedar_contextStore === undefined) {
|
|
44
|
+
return __cedar_getAsyncStoreInstance().run(
|
|
45
45
|
new Map(),
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
__cedar_handler,
|
|
47
|
+
__cedar_event,
|
|
48
|
+
__cedar_context
|
|
49
49
|
)
|
|
50
50
|
}
|
|
51
|
-
return
|
|
51
|
+
return __cedar_handler(__cedar_event, __cedar_context)
|
|
52
52
|
}
|
|
53
53
|
`;
|
|
54
54
|
return before + importStatement + renamed + wrappedHandler;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cedarjs/internal",
|
|
3
|
-
"version": "6.0.0-canary.
|
|
3
|
+
"version": "6.0.0-canary.2620",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/cedarjs/cedar.git",
|
|
@@ -169,13 +169,13 @@
|
|
|
169
169
|
"@babel/plugin-transform-react-jsx": "7.29.7",
|
|
170
170
|
"@babel/plugin-transform-typescript": "^7.26.8",
|
|
171
171
|
"@babel/traverse": "7.29.7",
|
|
172
|
-
"@cedarjs/babel-config": "6.0.0-canary.
|
|
173
|
-
"@cedarjs/cli-helpers": "6.0.0-canary.
|
|
174
|
-
"@cedarjs/graphql-server": "6.0.0-canary.
|
|
175
|
-
"@cedarjs/project-config": "6.0.0-canary.
|
|
176
|
-
"@cedarjs/router": "6.0.0-canary.
|
|
177
|
-
"@cedarjs/structure": "6.0.0-canary.
|
|
178
|
-
"@cedarjs/utils": "6.0.0-canary.
|
|
172
|
+
"@cedarjs/babel-config": "6.0.0-canary.2620",
|
|
173
|
+
"@cedarjs/cli-helpers": "6.0.0-canary.2620",
|
|
174
|
+
"@cedarjs/graphql-server": "6.0.0-canary.2620",
|
|
175
|
+
"@cedarjs/project-config": "6.0.0-canary.2620",
|
|
176
|
+
"@cedarjs/router": "6.0.0-canary.2620",
|
|
177
|
+
"@cedarjs/structure": "6.0.0-canary.2620",
|
|
178
|
+
"@cedarjs/utils": "6.0.0-canary.2620",
|
|
179
179
|
"@graphql-codegen/add": "6.0.1",
|
|
180
180
|
"@graphql-codegen/cli": "6.3.1",
|
|
181
181
|
"@graphql-codegen/client-preset": "5.3.0",
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
},
|
|
218
218
|
"devDependencies": {
|
|
219
219
|
"@arethetypeswrong/cli": "0.18.4",
|
|
220
|
-
"@cedarjs/framework-tools": "6.0.0-canary.
|
|
220
|
+
"@cedarjs/framework-tools": "6.0.0-canary.2620",
|
|
221
221
|
"concurrently": "9.2.1",
|
|
222
222
|
"graphql-tag": "2.12.6",
|
|
223
223
|
"publint": "0.3.21",
|