@odigos/aws-cdk 0.0.0

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.
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OdigosLayerResolver = void 0;
4
+ exports.odigosLayerName = odigosLayerName;
5
+ exports.functionScopeId = functionScopeId;
6
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
7
+ const lambda = require("aws-cdk-lib/aws-lambda");
8
+ const sam = require("aws-cdk-lib/aws-sam");
9
+ const layers_1 = require("./generated/layers");
10
+ const runtime_1 = require("./runtime");
11
+ const types_1 = require("./types");
12
+ /**
13
+ * Resolves the Odigos layer for a (language, architecture) to an `ILayerVersion`, and caches it so N
14
+ * functions of the same language and architecture share one layer construct — and, in `IN_ACCOUNT` mode,
15
+ * one nested SAR application rather than N copies of the same layer.
16
+ */
17
+ class OdigosLayerResolver {
18
+ constructor(scope, source) {
19
+ this.scope = scope;
20
+ this.source = source;
21
+ this.cache = new Map();
22
+ }
23
+ resolve(language, architecture) {
24
+ const key = `${language}/${architecture}`;
25
+ const cached = this.cache.get(key);
26
+ if (cached) {
27
+ return cached;
28
+ }
29
+ const layer = this.source === types_1.OdigosLayerSource.IN_ACCOUNT
30
+ ? this.fromSar(language, architecture)
31
+ : this.fromPublicArn(language, architecture);
32
+ this.cache.set(key, layer);
33
+ return layer;
34
+ }
35
+ /**
36
+ * The public layer version Odigos published in this stack's region, resolved from the table baked into
37
+ * this package at build time.
38
+ *
39
+ * A region with no entry throws rather than falling back to another region's ARN, which would not
40
+ * resolve, or to no layer, which would leave the function reporting healthy and exporting nothing.
41
+ */
42
+ fromPublicArn(language, architecture) {
43
+ const stack = aws_cdk_lib_1.Stack.of(this.scope);
44
+ const region = stack.region;
45
+ // An environment-agnostic stack has a token for its region, so there is no table lookup to do. This
46
+ // is worth catching explicitly: the alternative message would be about a region literally named
47
+ // "${Token[AWS.Region.6]}", which sends people looking in the wrong place entirely.
48
+ if (aws_cdk_lib_1.Token.isUnresolved(region)) {
49
+ throw new Error('Odigos: OdigosLayerSource.ODIGOS_PUBLIC needs a concrete region to look up the layer ARN, but ' +
50
+ 'this stack is environment-agnostic. Set `env: { region: "..." }` on the stack, or use ' +
51
+ 'OdigosLayerSource.IN_ACCOUNT, which resolves the layer at deploy time and works anywhere.');
52
+ }
53
+ const arn = layers_1.LAYER_ARNS[`${region}/${language}/${architecture}`];
54
+ if (!arn) {
55
+ const known = new Set(Object.keys(layers_1.LAYER_ARNS).map((k) => k.split('/')[0]));
56
+ throw new Error(`Odigos: no public ${language}/${architecture} layer published in ${region} ` +
57
+ `(@odigos/aws-cdk ${layers_1.ODIGOS_VERSION || 'unreleased'}). ` +
58
+ (known.size === 0
59
+ ? 'This build of the package has an empty layer table — it was built before the first release.'
60
+ : `Published regions: ${[...known].sort().join(', ')}.`) +
61
+ ' Use OdigosLayerSource.IN_ACCOUNT to deploy the layer into your own account instead.');
62
+ }
63
+ return lambda.LayerVersion.fromLayerVersionArn(this.scope, `OdigosLayer${this.constructSuffix(language, architecture)}`, arn);
64
+ }
65
+ /**
66
+ * Deploys the Odigos SAR application into this account as a nested stack and attaches the layer it
67
+ * creates.
68
+ *
69
+ * Pinning `semanticVersion` is what makes this reproducible: a SAR application version is immutable, so
70
+ * the pinned version resolves to the same layer bytes forever. Leaving it unpinned would let a later
71
+ * `cdk deploy` of unchanged code pick up a different layer.
72
+ */
73
+ fromSar(language, architecture) {
74
+ const applicationId = layers_1.SAR_APPLICATIONS[`${language}/${architecture}`];
75
+ if (!applicationId) {
76
+ throw new Error(`Odigos: no SAR application published for ${language}/${architecture} ` +
77
+ `(@odigos/aws-cdk ${layers_1.ODIGOS_VERSION || 'unreleased'}).`);
78
+ }
79
+ if (!layers_1.SAR_SEMANTIC_VERSION) {
80
+ throw new Error('Odigos: this build of @odigos/aws-cdk has no SAR semantic version baked in, so the application ' +
81
+ 'could only be deployed unpinned. Use a released version of the package.');
82
+ }
83
+ // CfnApplication is a SAM resource, so the stack needs the Serverless transform. addTransform is
84
+ // idempotent, so declaring it here is safe whether or not the app already uses SAM elsewhere.
85
+ aws_cdk_lib_1.Stack.of(this.scope).addTransform('AWS::Serverless-2016-10-31');
86
+ const suffix = this.constructSuffix(language, architecture);
87
+ const app = new sam.CfnApplication(this.scope, `OdigosLayerApp${suffix}`, {
88
+ location: {
89
+ applicationId,
90
+ semanticVersion: layers_1.SAR_SEMANTIC_VERSION,
91
+ },
92
+ });
93
+ return lambda.LayerVersion.fromLayerVersionArn(this.scope, `OdigosLayer${suffix}`, app.getAtt('Outputs.LayerVersionArn').toString());
94
+ }
95
+ /** `Python_X8664` — a construct-id-safe suffix that keeps ids stable and readable in the template. */
96
+ constructSuffix(language, architecture) {
97
+ const titled = language.charAt(0).toUpperCase() + language.slice(1);
98
+ return `${titled}${architecture.replace(/[^a-zA-Z0-9]/g, '')}`;
99
+ }
100
+ }
101
+ exports.OdigosLayerResolver = OdigosLayerResolver;
102
+ /**
103
+ * The layer name this package attaches, exposed so a stack can assert on it or build an allowlist.
104
+ *
105
+ * Deliberately identical to the name the connector publishes into an account
106
+ * (`store.OdigosLayerNamePrefix` + language + "-" + architecture). That is what lets a function
107
+ * instrumented here and later enabled as a connector source converge: the connector sees the same layer
108
+ * NAME, swaps its own version in rather than attaching a second OpenTelemetry layer, and recognises the
109
+ * layer as one it may manage.
110
+ */
111
+ function odigosLayerName(language, architecture) {
112
+ return (0, runtime_1.layerNameFor)(language, architecture);
113
+ }
114
+ /** Stable, human-readable construct id fragment for a function. Exported for the aspect. */
115
+ function functionScopeId(fn) {
116
+ return aws_cdk_lib_1.Names.nodeUniqueId(fn.node);
117
+ }
118
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGF5ZXItcmVzb2x2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbGF5ZXItcmVzb2x2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBdUlBLDBDQUVDO0FBR0QsMENBRUM7QUE5SUQsNkNBQWtEO0FBQ2xELGlEQUFpRDtBQUNqRCwyQ0FBMkM7QUFFM0MsK0NBQXdHO0FBQ3hHLHVDQUF5QztBQUN6QyxtQ0FBNEM7QUFFNUM7Ozs7R0FJRztBQUNILE1BQWEsbUJBQW1CO0lBRzlCLFlBQ21CLEtBQWdCLEVBQ2hCLE1BQXlCO1FBRHpCLFVBQUssR0FBTCxLQUFLLENBQVc7UUFDaEIsV0FBTSxHQUFOLE1BQU0sQ0FBbUI7UUFKM0IsVUFBSyxHQUFHLElBQUksR0FBRyxFQUFnQyxDQUFDO0lBSzlELENBQUM7SUFFRyxPQUFPLENBQUMsUUFBZ0IsRUFBRSxZQUFvQjtRQUNuRCxNQUFNLEdBQUcsR0FBRyxHQUFHLFFBQVEsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUMxQyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQyxJQUFJLE1BQU0sRUFBRSxDQUFDO1lBQ1gsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUNELE1BQU0sS0FBSyxHQUNULElBQUksQ0FBQyxNQUFNLEtBQUsseUJBQWlCLENBQUMsVUFBVTtZQUMxQyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDO1lBQ3RDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDM0IsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssYUFBYSxDQUFDLFFBQWdCLEVBQUUsWUFB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LEVBQUUsQ0FDakQsQ0FBQztJQUNKLENBQUM7SUFFRCxzR0FBc0c7SUFDOUYsZUFBZSxDQUFDLFFBQWdCLEVBQUUsWUFBb0I7UUFDNUQsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUUsR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BFLE9BQU8sR0FBRyxNQUFNLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUNqRSxDQUFDO0NBQ0Y7QUEvR0Qsa0RBK0dDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQixlQUFlLENBQUMsUUFBZ0IsRUFBRSxZQUFvQjtJQUNwRSxPQUFPLElBQUEsc0JBQVksRUFBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFDOUMsQ0FBQztBQUVELDRGQUE0RjtBQUM1RixTQUFnQixlQUFlLENBQUMsRUFBYTtJQUMzQyxPQUFPLG1CQUFLLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUNyQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmFtZXMsIFN0YWNrLCBUb2tlbiB9IGZyb20gJ2F3cy1jZGstbGliJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIHNhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc2FtJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgTEFZRVJfQVJOUywgT0RJR09TX1ZFUlNJT04sIFNBUl9BUFBMSUNBVElPTlMsIFNBUl9TRU1BTlRJQ19WRVJTSU9OIH0gZnJvbSAnLi9nZW5lcmF0ZWQvbGF5ZXJzJztcbmltcG9ydCB7IGxheWVyTmFtZUZvciB9IGZyb20gJy4vcnVudGltZSc7XG5pbXBvcnQgeyBPZGlnb3NMYXllclNvdXJjZSB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIFJlc29sdmVzIHRoZSBPZGlnb3MgbGF5ZXIgZm9yIGEgKGxhbmd1YWdlLCBhcmNoaXRlY3R1cmUpIHRvIGFuIGBJTGF5ZXJWZXJzaW9uYCwgYW5kIGNhY2hlcyBpdCBzbyBOXG4gKiBmdW5jdGlvbnMgb2YgdGhlIHNhbWUgbGFuZ3VhZ2UgYW5kIGFyY2hpdGVjdHVyZSBzaGFyZSBvbmUgbGF5ZXIgY29uc3RydWN0IOKAlCBhbmQsIGluIGBJTl9BQ0NPVU5UYCBtb2RlLFxuICogb25lIG5lc3RlZCBTQVIgYXBwbGljYXRpb24gcmF0aGVyIHRoYW4gTiBjb3BpZXMgb2YgdGhlIHNhbWUgbGF5ZXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBPZGlnb3NMYXllclJlc29sdmVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBjYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBsYW1iZGEuSUxheWVyVmVyc2lvbj4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNjb3BlOiBDb25zdHJ1Y3QsXG4gICAgcHJpdmF0ZSByZWFkb25seSBzb3VyY2U6IE9kaWdvc0xheWVyU291cmNlLFxuICApIHt9XG5cbiAgcHVibGljIHJlc29sdmUobGFuZ3VhZ2U6IHN0cmluZywgYXJjaGl0ZWN0dXJlOiBzdHJpbmcpOiBsYW1iZGEuSUxheWVyVmVyc2lvbiB7XG4gICAgY29uc3Qga2V5ID0gYCR7bGFuZ3VhZ2V9LyR7YXJjaGl0ZWN0dXJlfWA7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5jYWNoZS5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSB7XG4gICAgICByZXR1cm4gY2FjaGVkO1xuICAgIH1cbiAgICBjb25zdCBsYXllciA9XG4gICAgICB0aGlzLnNvdXJjZSA9PT0gT2RpZ29zTGF5ZXJTb3VyY2UuSU5fQUNDT1VOVFxuICAgICAgICA/IHRoaXMuZnJvbVNhcihsYW5ndWFnZSwgYXJjaGl0ZWN0dXJlKVxuICAgICAgICA6IHRoaXMuZnJvbVB1YmxpY0FybihsYW5ndWFnZSwgYXJjaGl0ZWN0dXJlKTtcbiAgICB0aGlzLmNhY2hlLnNldChrZXksIGxheWVyKTtcbiAgICByZXR1cm4gbGF5ZXI7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHB1YmxpYyBsYXllciB2ZXJzaW9uIE9kaWdvcyBwdWJsaXNoZWQgaW4gdGhpcyBzdGFjaydzIHJlZ2lvbiwgcmVzb2x2ZWQgZnJvbSB0aGUgdGFibGUgYmFrZWQgaW50b1xuICAgKiB0aGlzIHBhY2thZ2UgYXQgYnVpbGQgdGltZS5cbiAgICpcbiAgICogQSByZWdpb24gd2l0aCBubyBlbnRyeSB0aHJvd3MgcmF0aGVyIHRoYW4gZmFsbGluZyBiYWNrIHRvIGFub3RoZXIgcmVnaW9uJ3MgQVJOLCB3aGljaCB3b3VsZCBub3RcbiAgICogcmVzb2x2ZSwgb3IgdG8gbm8gbGF5ZXIsIHdoaWNoIHdvdWxkIGxlYXZlIHRoZSBmdW5jdGlvbiByZXBvcnRpbmcgaGVhbHRoeSBhbmQgZXhwb3J0aW5nIG5vdGhpbmcuXG4gICAqL1xuICBwcml2YXRlIGZyb21QdWJsaWNBcm4obGFuZ3VhZ2U6IHN0cmluZywgYXJjaGl0ZWN0dXJlOiBzdHJpbmcpOiBsYW1iZGEuSUxheWVyVmVyc2lvbiB7XG4gICAgY29uc3Qgc3RhY2sgPSBTdGFjay5vZih0aGlzLnNjb3BlKTtcbiAgICBjb25zdCByZWdpb24gPSBzdGFjay5yZWdpb247XG5cbiAgICAvLyBBbiBlbnZpcm9ubWVudC1hZ25vc3RpYyBzdGFjayBoYXMgYSB0b2tlbiBmb3IgaXRzIHJlZ2lvbiwgc28gdGhlcmUgaXMgbm8gdGFibGUgbG9va3VwIHRvIGRvLiBUaGlzXG4gICAgLy8gaXMgd29ydGggY2F0Y2hpbmcgZXhwbGljaXRseTogdGhlIGFsdGVybmF0aXZlIG1lc3NhZ2Ugd291bGQgYmUgYWJvdXQgYSByZWdpb24gbGl0ZXJhbGx5IG5hbWVkXG4gICAgLy8gXCIke1Rva2VuW0FXUy5SZWdpb24uNl19XCIsIHdoaWNoIHNlbmRzIHBlb3BsZSBsb29raW5nIGluIHRoZSB3cm9uZyBwbGFjZSBlbnRpcmVseS5cbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKHJlZ2lvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ09kaWdvczogT2RpZ29zTGF5ZXJTb3VyY2UuT0RJR09TX1BVQkxJQyBuZWVkcyBhIGNvbmNyZXRlIHJlZ2lvbiB0byBsb29rIHVwIHRoZSBsYXllciBBUk4sIGJ1dCAnICtcbiAgICAgICAgICAndGhpcyBzdGFjayBpcyBlbnZpcm9ubWVudC1hZ25vc3RpYy4gU2V0IGBlbnY6IHsgcmVnaW9uOiBcIi4uLlwiIH1gIG9uIHRoZSBzdGFjaywgb3IgdXNlICcgK1xuICAgICAgICAgICdPZGlnb3NMYXllclNvdXJjZS5JTl9BQ0NPVU5ULCB3aGljaCByZXNvbHZlcyB0aGUgbGF5ZXIgYXQgZGVwbG95IHRpbWUgYW5kIHdvcmtzIGFueXdoZXJlLicsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGFybiA9IExBWUVSX0FSTlNbYCR7cmVnaW9ufS8ke2xhbmd1YWdlfS8ke2FyY2hpdGVjdHVyZX1gXTtcbiAgICBpZiAoIWFybikge1xuICAgICAgY29uc3Qga25vd24gPSBuZXcgU2V0KE9iamVjdC5rZXlzKExBWUVSX0FSTlMpLm1hcCgoaykgPT4gay5zcGxpdCgnLycpWzBdKSk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBPZGlnb3M6IG5vIHB1YmxpYyAke2xhbmd1YWdlfS8ke2FyY2hpdGVjdHVyZX0gbGF5ZXIgcHVibGlzaGVkIGluICR7cmVnaW9ufSBgICtcbiAgICAgICAgICBgKEBvZGlnb3MvYXdzLWNkayAke09ESUdPU19WRVJTSU9OIHx8ICd1bnJlbGVhc2VkJ30pLiBgICtcbiAgICAgICAgICAoa25vd24uc2l6ZSA9PT0gMFxuICAgICAgICAgICAgPyAnVGhpcyBidWlsZCBvZiB0aGUgcGFja2FnZSBoYXMgYW4gZW1wdHkgbGF5ZXIgdGFibGUg4oCUIGl0IHdhcyBidWlsdCBiZWZvcmUgdGhlIGZpcnN0IHJlbGVhc2UuJ1xuICAgICAgICAgICAgOiBgUHVibGlzaGVkIHJlZ2lvbnM6ICR7Wy4uLmtub3duXS5zb3J0KCkuam9pbignLCAnKX0uYCkgK1xuICAgICAgICAgICcgVXNlIE9kaWdvc0xheWVyU291cmNlLklOX0FDQ09VTlQgdG8gZGVwbG95IHRoZSBsYXllciBpbnRvIHlvdXIgb3duIGFjY291bnQgaW5zdGVhZC4nLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbGFtYmRhLkxheWVyVmVyc2lvbi5mcm9tTGF5ZXJWZXJzaW9uQXJuKFxuICAgICAgdGhpcy5zY29wZSxcbiAgICAgIGBPZGlnb3NMYXllciR7dGhpcy5jb25zdHJ1Y3RTdWZmaXgobGFuZ3VhZ2UsIGFyY2hpdGVjdHVyZSl9YCxcbiAgICAgIGFybixcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIERlcGxveXMgdGhlIE9kaWdvcyBTQVIgYXBwbGljYXRpb24gaW50byB0aGlzIGFjY291bnQgYXMgYSBuZXN0ZWQgc3RhY2sgYW5kIGF0dGFjaGVzIHRoZSBsYXllciBpdFxuICAgKiBjcmVhdGVzLlxuICAgKlxuICAgKiBQaW5uaW5nIGBzZW1hbnRpY1ZlcnNpb25gIGlzIHdoYXQgbWFrZXMgdGhpcyByZXByb2R1Y2libGU6IGEgU0FSIGFwcGxpY2F0aW9uIHZlcnNpb24gaXMgaW1tdXRhYmxlLCBzb1xuICAgKiB0aGUgcGlubmVkIHZlcnNpb24gcmVzb2x2ZXMgdG8gdGhlIHNhbWUgbGF5ZXIgYnl0ZXMgZm9yZXZlci4gTGVhdmluZyBpdCB1bnBpbm5lZCB3b3VsZCBsZXQgYSBsYXRlclxuICAgKiBgY2RrIGRlcGxveWAgb2YgdW5jaGFuZ2VkIGNvZGUgcGljayB1cCBhIGRpZmZlcmVudCBsYXllci5cbiAgICovXG4gIHByaXZhdGUgZnJvbVNhcihsYW5ndWFnZTogc3RyaW5nLCBhcmNoaXRlY3R1cmU6IHN0cmluZyk6IGxhbWJkYS5JTGF5ZXJWZXJzaW9uIHtcbiAgICBjb25zdCBhcHBsaWNhdGlvbklkID0gU0FSX0FQUExJQ0FUSU9OU1tgJHtsYW5ndWFnZX0vJHthcmNoaXRlY3R1cmV9YF07XG4gICAgaWYgKCFhcHBsaWNhdGlvbklkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBPZGlnb3M6IG5vIFNBUiBhcHBsaWNhdGlvbiBwdWJsaXNoZWQgZm9yICR7bGFuZ3VhZ2V9LyR7YXJjaGl0ZWN0dXJlfSBgICtcbiAgICAgICAgICBgKEBvZGlnb3MvYXdzLWNkayAke09ESUdPU19WRVJTSU9OIHx8ICd1bnJlbGVhc2VkJ30pLmAsXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAoIVNBUl9TRU1BTlRJQ19WRVJTSU9OKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdPZGlnb3M6IHRoaXMgYnVpbGQgb2YgQG9kaWdvcy9hd3MtY2RrIGhhcyBubyBTQVIgc2VtYW50aWMgdmVyc2lvbiBiYWtlZCBpbiwgc28gdGhlIGFwcGxpY2F0aW9uICcgK1xuICAgICAgICAgICdjb3VsZCBvbmx5IGJlIGRlcGxveWVkIHVucGlubmVkLiBVc2UgYSByZWxlYXNlZCB2ZXJzaW9uIG9mIHRoZSBwYWNrYWdlLicsXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENmbkFwcGxpY2F0aW9uIGlzIGEgU0FNIHJlc291cmNlLCBzbyB0aGUgc3RhY2sgbmVlZHMgdGhlIFNlcnZlcmxlc3MgdHJhbnNmb3JtLiBhZGRUcmFuc2Zvcm0gaXNcbiAgICAvLyBpZGVtcG90ZW50LCBzbyBkZWNsYXJpbmcgaXQgaGVyZSBpcyBzYWZlIHdoZXRoZXIgb3Igbm90IHRoZSBhcHAgYWxyZWFkeSB1c2VzIFNBTSBlbHNld2hlcmUuXG4gICAgU3RhY2sub2YodGhpcy5zY29wZSkuYWRkVHJhbnNmb3JtKCdBV1M6OlNlcnZlcmxlc3MtMjAxNi0xMC0zMScpO1xuXG4gICAgY29uc3Qgc3VmZml4ID0gdGhpcy5jb25zdHJ1Y3RTdWZmaXgobGFuZ3VhZ2UsIGFyY2hpdGVjdHVyZSk7XG4gICAgY29uc3QgYXBwID0gbmV3IHNhbS5DZm5BcHBsaWNhdGlvbih0aGlzLnNjb3BlLCBgT2RpZ29zTGF5ZXJBcHAke3N1ZmZpeH1gLCB7XG4gICAgICBsb2NhdGlvbjoge1xuICAgICAgICBhcHBsaWNhdGlvbklkLFxuICAgICAgICBzZW1hbnRpY1ZlcnNpb246IFNBUl9TRU1BTlRJQ19WRVJTSU9OLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHJldHVybiBsYW1iZGEuTGF5ZXJWZXJzaW9uLmZyb21MYXllclZlcnNpb25Bcm4oXG4gICAgICB0aGlzLnNjb3BlLFxuICAgICAgYE9kaWdvc0xheWVyJHtzdWZmaXh9YCxcbiAgICAgIGFwcC5nZXRBdHQoJ091dHB1dHMuTGF5ZXJWZXJzaW9uQXJuJykudG9TdHJpbmcoKSxcbiAgICApO1xuICB9XG5cbiAgLyoqIGBQeXRob25fWDg2NjRgIOKAlCBhIGNvbnN0cnVjdC1pZC1zYWZlIHN1ZmZpeCB0aGF0IGtlZXBzIGlkcyBzdGFibGUgYW5kIHJlYWRhYmxlIGluIHRoZSB0ZW1wbGF0ZS4gKi9cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RTdWZmaXgobGFuZ3VhZ2U6IHN0cmluZywgYXJjaGl0ZWN0dXJlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHRpdGxlZCA9IGxhbmd1YWdlLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgbGFuZ3VhZ2Uuc2xpY2UoMSk7XG4gICAgcmV0dXJuIGAke3RpdGxlZH0ke2FyY2hpdGVjdHVyZS5yZXBsYWNlKC9bXmEtekEtWjAtOV0vZywgJycpfWA7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgbGF5ZXIgbmFtZSB0aGlzIHBhY2thZ2UgYXR0YWNoZXMsIGV4cG9zZWQgc28gYSBzdGFjayBjYW4gYXNzZXJ0IG9uIGl0IG9yIGJ1aWxkIGFuIGFsbG93bGlzdC5cbiAqXG4gKiBEZWxpYmVyYXRlbHkgaWRlbnRpY2FsIHRvIHRoZSBuYW1lIHRoZSBjb25uZWN0b3IgcHVibGlzaGVzIGludG8gYW4gYWNjb3VudFxuICogKGBzdG9yZS5PZGlnb3NMYXllck5hbWVQcmVmaXhgICsgbGFuZ3VhZ2UgKyBcIi1cIiArIGFyY2hpdGVjdHVyZSkuIFRoYXQgaXMgd2hhdCBsZXRzIGEgZnVuY3Rpb25cbiAqIGluc3RydW1lbnRlZCBoZXJlIGFuZCBsYXRlciBlbmFibGVkIGFzIGEgY29ubmVjdG9yIHNvdXJjZSBjb252ZXJnZTogdGhlIGNvbm5lY3RvciBzZWVzIHRoZSBzYW1lIGxheWVyXG4gKiBOQU1FLCBzd2FwcyBpdHMgb3duIHZlcnNpb24gaW4gcmF0aGVyIHRoYW4gYXR0YWNoaW5nIGEgc2Vjb25kIE9wZW5UZWxlbWV0cnkgbGF5ZXIsIGFuZCByZWNvZ25pc2VzIHRoZVxuICogbGF5ZXIgYXMgb25lIGl0IG1heSBtYW5hZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvZGlnb3NMYXllck5hbWUobGFuZ3VhZ2U6IHN0cmluZywgYXJjaGl0ZWN0dXJlOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gbGF5ZXJOYW1lRm9yKGxhbmd1YWdlLCBhcmNoaXRlY3R1cmUpO1xufVxuXG4vKiogU3RhYmxlLCBodW1hbi1yZWFkYWJsZSBjb25zdHJ1Y3QgaWQgZnJhZ21lbnQgZm9yIGEgZnVuY3Rpb24uIEV4cG9ydGVkIGZvciB0aGUgYXNwZWN0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZ1bmN0aW9uU2NvcGVJZChmbjogQ29uc3RydWN0KTogc3RyaW5nIHtcbiAgcmV0dXJuIE5hbWVzLm5vZGVVbmlxdWVJZChmbi5ub2RlKTtcbn1cbiJdfQ==
@@ -0,0 +1,49 @@
1
+ import { OdigosJavaHandlerDistro } from './types';
2
+ /**
3
+ * Resolves a Lambda runtime identifier (`python3.12`, `java21`, `nodejs22.x`) to the OTel layer language.
4
+ *
5
+ * Returns `undefined` for runtimes with no OpenTelemetry Lambda language layer — `dotnet*`, `provided.*`
6
+ * (Go and custom runtimes). The caller refuses to instrument rather than attaching a layer that does
7
+ * nothing, because a layer plus an exec wrapper that does not exist in it fails the function at cold start.
8
+ */
9
+ export declare function languageFromRuntime(runtimeName: string): string | undefined;
10
+ /**
11
+ * The `AWS_LAMBDA_EXEC_WRAPPER` value for a language.
12
+ *
13
+ * The wrapper script is LANGUAGE-SPECIFIC: Python ships `/opt/otel-instrument`; Node.js, Java and Ruby
14
+ * ship `/opt/otel-handler`. Setting the wrong one makes the layer bootstrap fail at cold start with
15
+ * `/opt/otel-instrument: does not exist` and the function errors out — which is why this is never a
16
+ * hardcoded constant at a call site.
17
+ *
18
+ * `distro` is only consulted for Java, whose layer ships four wrappers, one per handler interface.
19
+ */
20
+ export declare function execWrapperFor(language: string, distro?: OdigosJavaHandlerDistro): string;
21
+ /** Layer name for a language/architecture — `odigos-otel-python-arm64`. */
22
+ export declare function layerNameFor(language: string, architecture: string): string;
23
+ /** Environment variables to set on a function, as a plain map. */
24
+ export interface EnvVars {
25
+ readonly [key: string]: string;
26
+ }
27
+ /**
28
+ * Idempotently adds our loader value to a value the function already carries.
29
+ *
30
+ * `PYTHONPATH` is PREPENDED, so the layer's packages and its `sitecustomize` are found first; the
31
+ * `*_OPTIONS` variables are appended, so the customer's own flags keep precedence. Mirrors
32
+ * `addLoaderValue` in the connector.
33
+ */
34
+ export declare function addLoaderValue(existing: string | undefined, value: string, separator: string): string;
35
+ /**
36
+ * The environment that loads the language agent in web-server (AWS Lambda Web Adapter) mode.
37
+ *
38
+ * Web-adapter functions run a web server rather than a Lambda handler, and the adapter owns
39
+ * `AWS_LAMBDA_EXEC_WRAPPER` — so instrumentation is loaded through the language's own loader variable and
40
+ * the wrapper is left alone. Handler-mode instrumentation applied to one of these overwrites the
41
+ * adapter's wrapper and the function stops serving.
42
+ *
43
+ * @param existingLoaderValue the value the function already needs in its loader variable, which ours is
44
+ * joined to. CDK's `lambda.Function` exposes no way to read back an environment variable set elsewhere in
45
+ * the app, so a value that must be preserved has to be passed in explicitly.
46
+ */
47
+ export declare function webServerEnv(language: string, existingLoaderValue?: string): {
48
+ [key: string]: string;
49
+ };
package/lib/runtime.js ADDED
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.languageFromRuntime = languageFromRuntime;
4
+ exports.execWrapperFor = execWrapperFor;
5
+ exports.layerNameFor = layerNameFor;
6
+ exports.addLoaderValue = addLoaderValue;
7
+ exports.webServerEnv = webServerEnv;
8
+ const layers_1 = require("./generated/layers");
9
+ const types_1 = require("./types");
10
+ /**
11
+ * Runtime -> language, and language -> the exact env the layer expects.
12
+ *
13
+ * Mirrors `LanguageFromRuntime`, `execWrapperForLanguage` and `webServerLoader` in the connector's
14
+ * instrumentor. The data lives in ../../artifacts.json and reaches here through the generated module; the
15
+ * decisions live here.
16
+ */
17
+ /** Runtime prefixes that map to an OTel layer language. Prefix-matched, so `java8.al2` resolves to java. */
18
+ const LANGUAGE_PREFIXES = [
19
+ ['python', 'python'],
20
+ ['nodejs', 'nodejs'],
21
+ ['java', 'java'],
22
+ ['ruby', 'ruby'],
23
+ ];
24
+ /**
25
+ * Resolves a Lambda runtime identifier (`python3.12`, `java21`, `nodejs22.x`) to the OTel layer language.
26
+ *
27
+ * Returns `undefined` for runtimes with no OpenTelemetry Lambda language layer — `dotnet*`, `provided.*`
28
+ * (Go and custom runtimes). The caller refuses to instrument rather than attaching a layer that does
29
+ * nothing, because a layer plus an exec wrapper that does not exist in it fails the function at cold start.
30
+ */
31
+ function languageFromRuntime(runtimeName) {
32
+ for (const [prefix, language] of LANGUAGE_PREFIXES) {
33
+ if (runtimeName.startsWith(prefix)) {
34
+ return language;
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ /** Maps the Java distro enum to the wrapper script path the layer ships. */
40
+ const JAVA_DISTRO_WRAPPERS = {
41
+ [types_1.OdigosJavaHandlerDistro.OTEL_HANDLER]: '/opt/otel-handler',
42
+ [types_1.OdigosJavaHandlerDistro.OTEL_PROXY_HANDLER]: '/opt/otel-proxy-handler',
43
+ [types_1.OdigosJavaHandlerDistro.OTEL_SQS_HANDLER]: '/opt/otel-sqs-handler',
44
+ [types_1.OdigosJavaHandlerDistro.OTEL_STREAM_HANDLER]: '/opt/otel-stream-handler',
45
+ };
46
+ /**
47
+ * The `AWS_LAMBDA_EXEC_WRAPPER` value for a language.
48
+ *
49
+ * The wrapper script is LANGUAGE-SPECIFIC: Python ships `/opt/otel-instrument`; Node.js, Java and Ruby
50
+ * ship `/opt/otel-handler`. Setting the wrong one makes the layer bootstrap fail at cold start with
51
+ * `/opt/otel-instrument: does not exist` and the function errors out — which is why this is never a
52
+ * hardcoded constant at a call site.
53
+ *
54
+ * `distro` is only consulted for Java, whose layer ships four wrappers, one per handler interface.
55
+ */
56
+ function execWrapperFor(language, distro) {
57
+ if (language === 'java') {
58
+ return JAVA_DISTRO_WRAPPERS[distro ?? types_1.OdigosJavaHandlerDistro.OTEL_HANDLER];
59
+ }
60
+ const spec = layers_1.LANGUAGES[language];
61
+ if (!spec) {
62
+ throw new Error(`Odigos: no OpenTelemetry Lambda layer for language "${language}"`);
63
+ }
64
+ return spec.execWrapper;
65
+ }
66
+ /** Layer name for a language/architecture — `odigos-otel-python-arm64`. */
67
+ function layerNameFor(language, architecture) {
68
+ const spec = layers_1.LANGUAGES[language];
69
+ if (!spec) {
70
+ throw new Error(`Odigos: unknown language "${language}"`);
71
+ }
72
+ return `${spec.layerName}-${architecture}`;
73
+ }
74
+ /**
75
+ * Idempotently adds our loader value to a value the function already carries.
76
+ *
77
+ * `PYTHONPATH` is PREPENDED, so the layer's packages and its `sitecustomize` are found first; the
78
+ * `*_OPTIONS` variables are appended, so the customer's own flags keep precedence. Mirrors
79
+ * `addLoaderValue` in the connector.
80
+ */
81
+ function addLoaderValue(existing, value, separator) {
82
+ if (!existing) {
83
+ return value;
84
+ }
85
+ if (existing.includes(value)) {
86
+ return existing;
87
+ }
88
+ return separator === ':' ? `${value}${separator}${existing}` : `${existing}${separator}${value}`;
89
+ }
90
+ /**
91
+ * The environment that loads the language agent in web-server (AWS Lambda Web Adapter) mode.
92
+ *
93
+ * Web-adapter functions run a web server rather than a Lambda handler, and the adapter owns
94
+ * `AWS_LAMBDA_EXEC_WRAPPER` — so instrumentation is loaded through the language's own loader variable and
95
+ * the wrapper is left alone. Handler-mode instrumentation applied to one of these overwrites the
96
+ * adapter's wrapper and the function stops serving.
97
+ *
98
+ * @param existingLoaderValue the value the function already needs in its loader variable, which ours is
99
+ * joined to. CDK's `lambda.Function` exposes no way to read back an environment variable set elsewhere in
100
+ * the app, so a value that must be preserved has to be passed in explicitly.
101
+ */
102
+ function webServerEnv(language, existingLoaderValue) {
103
+ const spec = layers_1.LANGUAGES[language];
104
+ const loader = spec?.webServer;
105
+ if (!loader) {
106
+ throw new Error(`Odigos: ${types_1.OdigosInstrumentationMode.WEB_SERVER} mode is not supported for ${language} — ` +
107
+ 'there is no verified web-server loader for it. Use HANDLER mode, or leave the function uninstrumented.');
108
+ }
109
+ const env = {
110
+ [loader.envKey]: addLoaderValue(existingLoaderValue, loader.value, loader.separator),
111
+ };
112
+ // Python must be pinned to the HTTP OTLP exporter — the only one bundled in its layer. Other languages
113
+ // export correctly with their defaults, so nothing extra is written for them.
114
+ for (const [k, v] of Object.entries(loader.extraEnv)) {
115
+ env[k] = v;
116
+ }
117
+ return env;
118
+ }
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVudGltZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9ydW50aW1lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBMEJBLGtEQU9DO0FBb0JELHdDQVNDO0FBR0Qsb0NBTUM7QUFjRCx3Q0FRQztBQWNELG9DQXFCQztBQWhJRCwrQ0FBK0M7QUFDL0MsbUNBQTZFO0FBRTdFOzs7Ozs7R0FNRztBQUVILDRHQUE0RztBQUM1RyxNQUFNLGlCQUFpQixHQUE0QjtJQUNqRCxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUM7SUFDcEIsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDO0lBQ3BCLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUNoQixDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUM7Q0FDakIsQ0FBQztBQUVGOzs7Ozs7R0FNRztBQUNILFNBQWdCLG1CQUFtQixDQUFDLFdBQW1CO0lBQ3JELEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO1FBQ25ELElBQUksV0FBVyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQ25DLE9BQU8sUUFBUSxDQUFDO1FBQ2xCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELDRFQUE0RTtBQUM1RSxNQUFNLG9CQUFvQixHQUE4QjtJQUN0RCxDQUFDLCtCQUF1QixDQUFDLFlBQVksQ0FBQyxFQUFFLG1CQUFtQjtJQUMzRCxDQUFDLCtCQUF1QixDQUFDLGtCQUFrQixDQUFDLEVBQUUseUJBQXlCO0lBQ3ZFLENBQUMsK0JBQXVCLENBQUMsZ0JBQWdCLENBQUMsRUFBRSx1QkFBdUI7SUFDbkUsQ0FBQywrQkFBdUIsQ0FBQyxtQkFBbUIsQ0FBQyxFQUFFLDBCQUEwQjtDQUMxRSxDQUFDO0FBRUY7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLFFBQWdCLEVBQUUsTUFBZ0M7SUFDL0UsSUFBSSxRQUFRLEtBQUssTUFBTSxFQUFFLENBQUM7UUFDeEIsT0FBTyxvQkFBb0IsQ0FBQyxNQUFNLElBQUksK0JBQXVCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUNELE1BQU0sSUFBSSxHQUFHLGtCQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ1YsTUFBTSxJQUFJLEtBQUssQ0FBQyx1REFBdUQsUUFBUSxHQUFHLENBQUMsQ0FBQztJQUN0RixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDO0FBQzFCLENBQUM7QUFFRCwyRUFBMkU7QUFDM0UsU0FBZ0IsWUFBWSxDQUFDLFFBQWdCLEVBQUUsWUFBb0I7SUFDakUsTUFBTSxJQUFJLEdBQUcsa0JBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNqQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDVixNQUFNLElBQUksS0FBSyxDQUFDLDZCQUE2QixRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFDRCxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsSUFBSSxZQUFZLEVBQUUsQ0FBQztBQUM3QyxDQUFDO0FBT0Q7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLFFBQTRCLEVBQUUsS0FBYSxFQUFFLFNBQWlCO0lBQzNGLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNkLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzdCLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFDRCxPQUFPLFNBQVMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxHQUFHLFNBQVMsR0FBRyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxRQUFRLEdBQUcsU0FBUyxHQUFHLEtBQUssRUFBRSxDQUFDO0FBQ25HLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILFNBQWdCLFlBQVksQ0FDMUIsUUFBZ0IsRUFDaEIsbUJBQTRCO0lBRTVCLE1BQU0sSUFBSSxHQUFHLGtCQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxFQUFFLFNBQVMsQ0FBQztJQUMvQixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixNQUFNLElBQUksS0FBSyxDQUNiLFdBQVcsaUNBQXlCLENBQUMsVUFBVSw4QkFBOEIsUUFBUSxLQUFLO1lBQ3hGLHdHQUF3RyxDQUMzRyxDQUFDO0lBQ0osQ0FBQztJQUNELE1BQU0sR0FBRyxHQUE4QjtRQUNyQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxjQUFjLENBQUMsbUJBQW1CLEVBQUUsTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsU0FBUyxDQUFDO0tBQ3JGLENBQUM7SUFDRix1R0FBdUc7SUFDdkcsOEVBQThFO0lBQzlFLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQ3JELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDYixDQUFDO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTEFOR1VBR0VTIH0gZnJvbSAnLi9nZW5lcmF0ZWQvbGF5ZXJzJztcbmltcG9ydCB7IE9kaWdvc0luc3RydW1lbnRhdGlvbk1vZGUsIE9kaWdvc0phdmFIYW5kbGVyRGlzdHJvIH0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogUnVudGltZSAtPiBsYW5ndWFnZSwgYW5kIGxhbmd1YWdlIC0+IHRoZSBleGFjdCBlbnYgdGhlIGxheWVyIGV4cGVjdHMuXG4gKlxuICogTWlycm9ycyBgTGFuZ3VhZ2VGcm9tUnVudGltZWAsIGBleGVjV3JhcHBlckZvckxhbmd1YWdlYCBhbmQgYHdlYlNlcnZlckxvYWRlcmAgaW4gdGhlIGNvbm5lY3RvcidzXG4gKiBpbnN0cnVtZW50b3IuIFRoZSBkYXRhIGxpdmVzIGluIC4uLy4uL2FydGlmYWN0cy5qc29uIGFuZCByZWFjaGVzIGhlcmUgdGhyb3VnaCB0aGUgZ2VuZXJhdGVkIG1vZHVsZTsgdGhlXG4gKiBkZWNpc2lvbnMgbGl2ZSBoZXJlLlxuICovXG5cbi8qKiBSdW50aW1lIHByZWZpeGVzIHRoYXQgbWFwIHRvIGFuIE9UZWwgbGF5ZXIgbGFuZ3VhZ2UuIFByZWZpeC1tYXRjaGVkLCBzbyBgamF2YTguYWwyYCByZXNvbHZlcyB0byBqYXZhLiAqL1xuY29uc3QgTEFOR1VBR0VfUFJFRklYRVM6IEFycmF5PFtzdHJpbmcsIHN0cmluZ10+ID0gW1xuICBbJ3B5dGhvbicsICdweXRob24nXSxcbiAgWydub2RlanMnLCAnbm9kZWpzJ10sXG4gIFsnamF2YScsICdqYXZhJ10sXG4gIFsncnVieScsICdydWJ5J10sXG5dO1xuXG4vKipcbiAqIFJlc29sdmVzIGEgTGFtYmRhIHJ1bnRpbWUgaWRlbnRpZmllciAoYHB5dGhvbjMuMTJgLCBgamF2YTIxYCwgYG5vZGVqczIyLnhgKSB0byB0aGUgT1RlbCBsYXllciBsYW5ndWFnZS5cbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIGZvciBydW50aW1lcyB3aXRoIG5vIE9wZW5UZWxlbWV0cnkgTGFtYmRhIGxhbmd1YWdlIGxheWVyIOKAlCBgZG90bmV0KmAsIGBwcm92aWRlZC4qYFxuICogKEdvIGFuZCBjdXN0b20gcnVudGltZXMpLiBUaGUgY2FsbGVyIHJlZnVzZXMgdG8gaW5zdHJ1bWVudCByYXRoZXIgdGhhbiBhdHRhY2hpbmcgYSBsYXllciB0aGF0IGRvZXNcbiAqIG5vdGhpbmcsIGJlY2F1c2UgYSBsYXllciBwbHVzIGFuIGV4ZWMgd3JhcHBlciB0aGF0IGRvZXMgbm90IGV4aXN0IGluIGl0IGZhaWxzIHRoZSBmdW5jdGlvbiBhdCBjb2xkIHN0YXJ0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGFuZ3VhZ2VGcm9tUnVudGltZShydW50aW1lTmFtZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgZm9yIChjb25zdCBbcHJlZml4LCBsYW5ndWFnZV0gb2YgTEFOR1VBR0VfUFJFRklYRVMpIHtcbiAgICBpZiAocnVudGltZU5hbWUuc3RhcnRzV2l0aChwcmVmaXgpKSB7XG4gICAgICByZXR1cm4gbGFuZ3VhZ2U7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKiBNYXBzIHRoZSBKYXZhIGRpc3RybyBlbnVtIHRvIHRoZSB3cmFwcGVyIHNjcmlwdCBwYXRoIHRoZSBsYXllciBzaGlwcy4gKi9cbmNvbnN0IEpBVkFfRElTVFJPX1dSQVBQRVJTOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge1xuICBbT2RpZ29zSmF2YUhhbmRsZXJEaXN0cm8uT1RFTF9IQU5ETEVSXTogJy9vcHQvb3RlbC1oYW5kbGVyJyxcbiAgW09kaWdvc0phdmFIYW5kbGVyRGlzdHJvLk9URUxfUFJPWFlfSEFORExFUl06ICcvb3B0L290ZWwtcHJveHktaGFuZGxlcicsXG4gIFtPZGlnb3NKYXZhSGFuZGxlckRpc3Ryby5PVEVMX1NRU19IQU5ETEVSXTogJy9vcHQvb3RlbC1zcXMtaGFuZGxlcicsXG4gIFtPZGlnb3NKYXZhSGFuZGxlckRpc3Ryby5PVEVMX1NUUkVBTV9IQU5ETEVSXTogJy9vcHQvb3RlbC1zdHJlYW0taGFuZGxlcicsXG59O1xuXG4vKipcbiAqIFRoZSBgQVdTX0xBTUJEQV9FWEVDX1dSQVBQRVJgIHZhbHVlIGZvciBhIGxhbmd1YWdlLlxuICpcbiAqIFRoZSB3cmFwcGVyIHNjcmlwdCBpcyBMQU5HVUFHRS1TUEVDSUZJQzogUHl0aG9uIHNoaXBzIGAvb3B0L290ZWwtaW5zdHJ1bWVudGA7IE5vZGUuanMsIEphdmEgYW5kIFJ1YnlcbiAqIHNoaXAgYC9vcHQvb3RlbC1oYW5kbGVyYC4gU2V0dGluZyB0aGUgd3Jvbmcgb25lIG1ha2VzIHRoZSBsYXllciBib290c3RyYXAgZmFpbCBhdCBjb2xkIHN0YXJ0IHdpdGhcbiAqIGAvb3B0L290ZWwtaW5zdHJ1bWVudDogZG9lcyBub3QgZXhpc3RgIGFuZCB0aGUgZnVuY3Rpb24gZXJyb3JzIG91dCDigJQgd2hpY2ggaXMgd2h5IHRoaXMgaXMgbmV2ZXIgYVxuICogaGFyZGNvZGVkIGNvbnN0YW50IGF0IGEgY2FsbCBzaXRlLlxuICpcbiAqIGBkaXN0cm9gIGlzIG9ubHkgY29uc3VsdGVkIGZvciBKYXZhLCB3aG9zZSBsYXllciBzaGlwcyBmb3VyIHdyYXBwZXJzLCBvbmUgcGVyIGhhbmRsZXIgaW50ZXJmYWNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZXhlY1dyYXBwZXJGb3IobGFuZ3VhZ2U6IHN0cmluZywgZGlzdHJvPzogT2RpZ29zSmF2YUhhbmRsZXJEaXN0cm8pOiBzdHJpbmcge1xuICBpZiAobGFuZ3VhZ2UgPT09ICdqYXZhJykge1xuICAgIHJldHVybiBKQVZBX0RJU1RST19XUkFQUEVSU1tkaXN0cm8gPz8gT2RpZ29zSmF2YUhhbmRsZXJEaXN0cm8uT1RFTF9IQU5ETEVSXTtcbiAgfVxuICBjb25zdCBzcGVjID0gTEFOR1VBR0VTW2xhbmd1YWdlXTtcbiAgaWYgKCFzcGVjKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPZGlnb3M6IG5vIE9wZW5UZWxlbWV0cnkgTGFtYmRhIGxheWVyIGZvciBsYW5ndWFnZSBcIiR7bGFuZ3VhZ2V9XCJgKTtcbiAgfVxuICByZXR1cm4gc3BlYy5leGVjV3JhcHBlcjtcbn1cblxuLyoqIExheWVyIG5hbWUgZm9yIGEgbGFuZ3VhZ2UvYXJjaGl0ZWN0dXJlIOKAlCBgb2RpZ29zLW90ZWwtcHl0aG9uLWFybTY0YC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBsYXllck5hbWVGb3IobGFuZ3VhZ2U6IHN0cmluZywgYXJjaGl0ZWN0dXJlOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBzcGVjID0gTEFOR1VBR0VTW2xhbmd1YWdlXTtcbiAgaWYgKCFzcGVjKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBPZGlnb3M6IHVua25vd24gbGFuZ3VhZ2UgXCIke2xhbmd1YWdlfVwiYCk7XG4gIH1cbiAgcmV0dXJuIGAke3NwZWMubGF5ZXJOYW1lfS0ke2FyY2hpdGVjdHVyZX1gO1xufVxuXG4vKiogRW52aXJvbm1lbnQgdmFyaWFibGVzIHRvIHNldCBvbiBhIGZ1bmN0aW9uLCBhcyBhIHBsYWluIG1hcC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRW52VmFycyB7XG4gIHJlYWRvbmx5IFtrZXk6IHN0cmluZ106IHN0cmluZztcbn1cblxuLyoqXG4gKiBJZGVtcG90ZW50bHkgYWRkcyBvdXIgbG9hZGVyIHZhbHVlIHRvIGEgdmFsdWUgdGhlIGZ1bmN0aW9uIGFscmVhZHkgY2Fycmllcy5cbiAqXG4gKiBgUFlUSE9OUEFUSGAgaXMgUFJFUEVOREVELCBzbyB0aGUgbGF5ZXIncyBwYWNrYWdlcyBhbmQgaXRzIGBzaXRlY3VzdG9taXplYCBhcmUgZm91bmQgZmlyc3Q7IHRoZVxuICogYCpfT1BUSU9OU2AgdmFyaWFibGVzIGFyZSBhcHBlbmRlZCwgc28gdGhlIGN1c3RvbWVyJ3Mgb3duIGZsYWdzIGtlZXAgcHJlY2VkZW5jZS4gTWlycm9yc1xuICogYGFkZExvYWRlclZhbHVlYCBpbiB0aGUgY29ubmVjdG9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYWRkTG9hZGVyVmFsdWUoZXhpc3Rpbmc6IHN0cmluZyB8IHVuZGVmaW5lZCwgdmFsdWU6IHN0cmluZywgc2VwYXJhdG9yOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAoIWV4aXN0aW5nKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChleGlzdGluZy5pbmNsdWRlcyh2YWx1ZSkpIHtcbiAgICByZXR1cm4gZXhpc3Rpbmc7XG4gIH1cbiAgcmV0dXJuIHNlcGFyYXRvciA9PT0gJzonID8gYCR7dmFsdWV9JHtzZXBhcmF0b3J9JHtleGlzdGluZ31gIDogYCR7ZXhpc3Rpbmd9JHtzZXBhcmF0b3J9JHt2YWx1ZX1gO1xufVxuXG4vKipcbiAqIFRoZSBlbnZpcm9ubWVudCB0aGF0IGxvYWRzIHRoZSBsYW5ndWFnZSBhZ2VudCBpbiB3ZWItc2VydmVyIChBV1MgTGFtYmRhIFdlYiBBZGFwdGVyKSBtb2RlLlxuICpcbiAqIFdlYi1hZGFwdGVyIGZ1bmN0aW9ucyBydW4gYSB3ZWIgc2VydmVyIHJhdGhlciB0aGFuIGEgTGFtYmRhIGhhbmRsZXIsIGFuZCB0aGUgYWRhcHRlciBvd25zXG4gKiBgQVdTX0xBTUJEQV9FWEVDX1dSQVBQRVJgIOKAlCBzbyBpbnN0cnVtZW50YXRpb24gaXMgbG9hZGVkIHRocm91Z2ggdGhlIGxhbmd1YWdlJ3Mgb3duIGxvYWRlciB2YXJpYWJsZSBhbmRcbiAqIHRoZSB3cmFwcGVyIGlzIGxlZnQgYWxvbmUuIEhhbmRsZXItbW9kZSBpbnN0cnVtZW50YXRpb24gYXBwbGllZCB0byBvbmUgb2YgdGhlc2Ugb3ZlcndyaXRlcyB0aGVcbiAqIGFkYXB0ZXIncyB3cmFwcGVyIGFuZCB0aGUgZnVuY3Rpb24gc3RvcHMgc2VydmluZy5cbiAqXG4gKiBAcGFyYW0gZXhpc3RpbmdMb2FkZXJWYWx1ZSB0aGUgdmFsdWUgdGhlIGZ1bmN0aW9uIGFscmVhZHkgbmVlZHMgaW4gaXRzIGxvYWRlciB2YXJpYWJsZSwgd2hpY2ggb3VycyBpc1xuICogam9pbmVkIHRvLiBDREsncyBgbGFtYmRhLkZ1bmN0aW9uYCBleHBvc2VzIG5vIHdheSB0byByZWFkIGJhY2sgYW4gZW52aXJvbm1lbnQgdmFyaWFibGUgc2V0IGVsc2V3aGVyZSBpblxuICogdGhlIGFwcCwgc28gYSB2YWx1ZSB0aGF0IG11c3QgYmUgcHJlc2VydmVkIGhhcyB0byBiZSBwYXNzZWQgaW4gZXhwbGljaXRseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHdlYlNlcnZlckVudihcbiAgbGFuZ3VhZ2U6IHN0cmluZyxcbiAgZXhpc3RpbmdMb2FkZXJWYWx1ZT86IHN0cmluZyxcbik6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0ge1xuICBjb25zdCBzcGVjID0gTEFOR1VBR0VTW2xhbmd1YWdlXTtcbiAgY29uc3QgbG9hZGVyID0gc3BlYz8ud2ViU2VydmVyO1xuICBpZiAoIWxvYWRlcikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBPZGlnb3M6ICR7T2RpZ29zSW5zdHJ1bWVudGF0aW9uTW9kZS5XRUJfU0VSVkVSfSBtb2RlIGlzIG5vdCBzdXBwb3J0ZWQgZm9yICR7bGFuZ3VhZ2V9IOKAlCBgICtcbiAgICAgICAgJ3RoZXJlIGlzIG5vIHZlcmlmaWVkIHdlYi1zZXJ2ZXIgbG9hZGVyIGZvciBpdC4gVXNlIEhBTkRMRVIgbW9kZSwgb3IgbGVhdmUgdGhlIGZ1bmN0aW9uIHVuaW5zdHJ1bWVudGVkLicsXG4gICAgKTtcbiAgfVxuICBjb25zdCBlbnY6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0gPSB7XG4gICAgW2xvYWRlci5lbnZLZXldOiBhZGRMb2FkZXJWYWx1ZShleGlzdGluZ0xvYWRlclZhbHVlLCBsb2FkZXIudmFsdWUsIGxvYWRlci5zZXBhcmF0b3IpLFxuICB9O1xuICAvLyBQeXRob24gbXVzdCBiZSBwaW5uZWQgdG8gdGhlIEhUVFAgT1RMUCBleHBvcnRlciDigJQgdGhlIG9ubHkgb25lIGJ1bmRsZWQgaW4gaXRzIGxheWVyLiBPdGhlciBsYW5ndWFnZXNcbiAgLy8gZXhwb3J0IGNvcnJlY3RseSB3aXRoIHRoZWlyIGRlZmF1bHRzLCBzbyBub3RoaW5nIGV4dHJhIGlzIHdyaXR0ZW4gZm9yIHRoZW0uXG4gIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKGxvYWRlci5leHRyYUVudikpIHtcbiAgICBlbnZba10gPSB2O1xuICB9XG4gIHJldHVybiBlbnY7XG59XG4iXX0=