Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"temporalio": "file:packages/meta"
},
"devDependencies": {
"@eslint/js": "^9.26.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/core": "^1.25.1",
"@opentelemetry/sdk-node": "^0.52.1",
Expand All @@ -66,7 +67,6 @@
"@types/node": "^20.10.8",
"@types/stack-utils": "^2.0.3",
"@types/supports-color": "^8.1.3",
"@eslint/js": "^9.26.0",
"@typescript-eslint/eslint-plugin": "^8.10.0",
"@typescript-eslint/parser": "^8.10.0",
"arg": "^5.0.2",
Expand Down Expand Up @@ -94,5 +94,10 @@
"version": "10.27.0",
"onFail": "warn"
}
},
"pnpm": {
"patchedDependencies": {
"protobufjs@7.5.5": "patches/protobufjs@7.5.5.patch"
}
}
}
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"devDependencies": {
"@types/uuid": "^9.0.7",
"protobufjs": "^7.2.5"
"protobufjs": "^7.5.5"
},
"bugs": {
"url": "https://github.com/temporalio/sdk-typescript/issues"
Expand Down
2 changes: 1 addition & 1 deletion packages/cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"abort-controller": "^3.0.0"
},
"devDependencies": {
"protobufjs": "^7.2.5"
"protobufjs": "^7.5.5"
},
"bugs": {
"url": "https://github.com/temporalio/sdk-typescript/issues"
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"proto3-json-serializer": "^2.0.0"
},
"devDependencies": {
"protobufjs": "^7.2.5"
"protobufjs": "^7.5.5"
},
"bugs": {
"url": "https://github.com/temporalio/sdk-typescript/issues"
Expand Down
53 changes: 28 additions & 25 deletions packages/core-bridge/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/core-bridge/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ temporalio-sdk-core = { version = "*", path = "./sdk-core/crates/sdk-core", feat
"ephemeral-server",
] }
temporalio-client = { version = "*", path = "./sdk-core/crates/client" }
temporalio-common = { version = "*", path = "./sdk-core/crates/common" }
temporalio-common = { version = "*", path = "./sdk-core/crates/common", features = [
"otel",
] }
thiserror = "2"
tokio = "1.13"
tokio-stream = "0.1"
Expand Down
2 changes: 1 addition & 1 deletion packages/core-bridge/sdk-core
2 changes: 1 addition & 1 deletion packages/proto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"license": "MIT",
"dependencies": {
"long": "^5.2.3",
"protobufjs": "^7.2.5"
"protobufjs": "7.5.5"
},
"devDependencies": {
"glob": "^10.3.10",
Expand Down
55 changes: 44 additions & 11 deletions packages/proto/src/patch-protobuf-root.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
const ROOT_PROPS = [
// Properties used internally by protobufjs on Namespace/ReflectionObject instances.
// A protobuf package component that happens to share one of these names must not be
// promoted to a direct property, or it would corrupt protobufjs's internal state.
// (Such types are still reachable via root.lookup() or root.nested traversal.)
const ROOT_PROPS = new Set([
'options',
'parsedOptions',
'name',
Expand All @@ -8,7 +12,7 @@ const ROOT_PROPS = [
'filename',
'nested',
'_nestedArray',
];
]);

/**
* Create a version of `root` with non-nested namespaces to match the generated types.
Expand All @@ -18,26 +22,55 @@ const ROOT_PROPS = [
* @returns A new patched `root`
*/
export function patchProtobufRoot<T extends Record<string, unknown>>(root: T): T {
return _patchProtobufRoot(root);
const patched = _patchProtobufRoot(root);

// Protobufjs >=7.5.2 added a fast-path cache in Namespace#lookup() that accesses
// `this.root._fullyQualifiedObjects`. The `root` accessor is defined as a non-enumerable
// getter on `ReflectionObject.prototype`, so it is not copied by `for...in` loops.
// When the patched root is imported via `import * as proto from '@temporalio/proto'`,
// TypeScript's `__importStar` helper wraps the CJS module in a plain object by iterating
// own enumerable properties with `for...in` + `hasOwnProperty`. Because `root` is
// non-enumerable, it is skipped, the wrapper's `root` is `undefined`, and any subsequent
// `this.root._fullyQualifiedObjects` access crashes.
// Defining `root` as an own **enumerable** getter ensures `__importStar` includes it in
// the wrapper, so that `wrapper.root` delegates back to the patched root (which has the
// proper `_fullyQualifiedObjects` map and full prototype chain).
if (!Object.getOwnPropertyDescriptor(patched, 'root')) {
Object.defineProperty(patched, 'root', {
get(this: any) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
let ptr = this;
while (ptr.parent !== null) ptr = ptr.parent;
return ptr;
},
enumerable: true,
configurable: true,
});
}

return patched;
}

function _patchProtobufRoot<T extends Record<string, unknown>>(root: T, name?: string): T {
const newRoot = new (root.constructor as any)(isNamespace(root) ? name : {});
for (const key in root) {
// 'root' is a getter-only accessor defined on ReflectionObject.prototype. Trying to
// assign it as a plain property on a new Root/Namespace instance throws in strict mode.
// It is also safe to skip because each object correctly resolves its own root at runtime
// by traversing the parent chain. The top-level own enumerable getter is added separately
// by patchProtobufRoot() after recursion completes.
if (key === 'root') continue;
newRoot[key] = root[key];
}

if (isRecord(root.nested)) {
for (const typeOrNamespace in root.nested) {
const value = root.nested[typeOrNamespace];
if (ROOT_PROPS.includes(typeOrNamespace)) {
console.log(
`patchProtobufRoot warning: overriding property '${typeOrNamespace}' that is used by protobufjs with the '${typeOrNamespace}' protobuf ${
isNamespace(value) ? 'namespace' : 'type'
}. This may result in protobufjs not working property.`
);
}
// Skip names that protobufjs uses internally — overriding them would corrupt
// the namespace object's internal state. Types/namespaces with these names are
// still reachable via root.lookup() or by traversing root.nested manually.
if (ROOT_PROPS.has(typeOrNamespace)) continue;

const value = root.nested[typeOrNamespace];
if (isNamespace(value)) {
newRoot[typeOrNamespace] = _patchProtobufRoot(value, typeOrNamespace);
} else if (isType(value)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"long": "^5.2.3",
"nexus-rpc": "^0.0.2",
"proto3-json-serializer": "^2.0.0",
"protobufjs": "^7.2.5",
"protobufjs": "7.5.5",
"protobufjs-cli": "^1.1.2",
"rxjs": "7.8.1",
"stack-utils": "^2.0.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"memfs": "^4.6.0",
"nexus-rpc": "^0.0.2",
"proto3-json-serializer": "^2.0.0",
"protobufjs": "^7.2.5",
"protobufjs": "^7.5.5",
"rxjs": "^7.8.1",
"source-map": "^0.7.4",
"source-map-loader": "^4.0.2",
Expand Down
19 changes: 19 additions & 0 deletions patches/protobufjs@7.5.5.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
diff --git a/src/parse.js b/src/parse.js
index 9c3cc27539f2cd555a1306fea0dfa0ef88eb8cc0..4317be0104461c876298579a5218c27a2e5ac474 100644
--- a/src/parse.js
+++ b/src/parse.js
@@ -722,8 +722,12 @@ function parse(source, root, options) {
var lastValue;
if (skip("[", true)) {
do {
- lastValue = readValue(true);
- value.push(lastValue);
+ if (peek() === "{")
+ parseOptionValue({}, name + "." + token); // consume without recording
+ else {
+ lastValue = readValue(true);
+ value.push(lastValue);
+ }
} while (skip(",", true));
skip("]");
if (typeof lastValue !== "undefined") {
Loading
Loading