@fireemu/darwin-x64 0.44.0 → 0.46.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.
- package/README.md +1 -1
- package/bin/fireemu +2 -2
- package/bin/runner-node/index.mjs +25 -3
- package/bin/runner-python/fireemu_runner/events.py +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @fireemu/darwin-x64
|
|
2
2
|
|
|
3
3
|
The [fireemu](https://www.npmjs.com/package/fireemu) daemon built for `darwin-x64`
|
|
4
|
-
(Rust target `x86_64-apple-darwin`), version 0.
|
|
4
|
+
(Rust target `x86_64-apple-darwin`), version 0.46.0.
|
|
5
5
|
|
|
6
6
|
macOS 13 or newer on Intel. Cross-compiled from the Apple silicon runner against the same universal SDK; its unit tests run on the arm64 host, which builds the same code.
|
|
7
7
|
|
package/bin/fireemu
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/bin/fireemu
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 41153456 bytes
|
|
4
|
+
sha256: 81ae962260c9ec10a5a70ec9a8474b19db989b9cdaefb9a47c97cf16fd848818
|
|
@@ -724,14 +724,14 @@ function ignoredBlocking(base, eventType) {
|
|
|
724
724
|
return ignored(base, "blocking", "unsupported", `blocking identity event ${eventType} is not served`);
|
|
725
725
|
}
|
|
726
726
|
|
|
727
|
-
//
|
|
727
|
+
// Trigger families outside the served surface; exact supported types are handled first.
|
|
728
728
|
// The event-type substring is matched the way `getServiceFromEventType` matches it.
|
|
729
729
|
const DEFERRED_TRIGGER_PRODUCTS = [
|
|
730
730
|
{
|
|
731
731
|
match: (type) => type.includes("remoteconfig"),
|
|
732
732
|
triggerType: "remoteConfig",
|
|
733
733
|
scope: "deferred",
|
|
734
|
-
reason: "deferred: Remote Config
|
|
734
|
+
reason: "deferred: only Remote Config update triggers are served by the local injection action",
|
|
735
735
|
},
|
|
736
736
|
{
|
|
737
737
|
match: (type) => type.includes("dataconnect"),
|
|
@@ -768,6 +768,12 @@ function deferredProduct(type) {
|
|
|
768
768
|
// firebase-functions v1 triggers: legacy event types and a resource pattern.
|
|
769
769
|
function describeV1Event(base, type, resource, schedule, retry) {
|
|
770
770
|
const v1 = { v1: true };
|
|
771
|
+
if (type === "google.firebase.remoteconfig.update") {
|
|
772
|
+
if (resource !== `projects/${process.env.GCLOUD_PROJECT}`) {
|
|
773
|
+
return ignored(base, "remoteConfig", "unsupported", "Remote Config resource must name the runtime project");
|
|
774
|
+
}
|
|
775
|
+
return { ...base, ...v1, retry, trigger: { type: "remoteConfig" } };
|
|
776
|
+
}
|
|
771
777
|
const dbMatch = type.match(/^providers\/google\.firebase\.database\/eventTypes\/ref\.(create|update|delete|write)$/);
|
|
772
778
|
if (dbMatch) {
|
|
773
779
|
resource = triggerString(resource, "eventTrigger.resource", { optional: true, allowEmpty: true }) ?? "";
|
|
@@ -1020,6 +1026,9 @@ function describe(name, fn, instrumentation) {
|
|
|
1020
1026
|
},
|
|
1021
1027
|
};
|
|
1022
1028
|
}
|
|
1029
|
+
if (type === "google.firebase.remoteconfig.remoteConfig.v1.updated" && et.channel === undefined) {
|
|
1030
|
+
return { ...base, trigger: { type: "remoteConfig" } };
|
|
1031
|
+
}
|
|
1023
1032
|
if (type === "google.cloud.pubsub.topic.v1.messagePublished") {
|
|
1024
1033
|
const topic = triggerString(triggerRecord(et.eventFilters, "eventFilters").topic, "eventFilters.topic");
|
|
1025
1034
|
const projectedTopic = topic.replace(/^.*\/topics\//, "");
|
|
@@ -1155,6 +1164,8 @@ const strictProfile = () => process.env.FIREEMU_HTTP_PROFILE === "strict";
|
|
|
1155
1164
|
function v1Context(msg) {
|
|
1156
1165
|
const event = msg.event;
|
|
1157
1166
|
switch (msg.trigger) {
|
|
1167
|
+
case "remoteConfig":
|
|
1168
|
+
return event.context;
|
|
1158
1169
|
case "database": {
|
|
1159
1170
|
const operation = {created:"create",updated:"update",deleted:"delete",written:"write"}[event.type.split(".").at(-1)];
|
|
1160
1171
|
const context = {
|
|
@@ -1497,6 +1508,8 @@ function firestoreProtoTimestamp(value) {
|
|
|
1497
1508
|
function firestoreProtoFields(fields) {
|
|
1498
1509
|
return Object.fromEntries(Object.entries(fields ?? {}).map(([key, value]) => {
|
|
1499
1510
|
const converted = { ...value };
|
|
1511
|
+
// protobufjs skips null members; the NullValue enum must be its numeric zero.
|
|
1512
|
+
if (value.nullValue === null) converted.nullValue = 0;
|
|
1500
1513
|
if (value.timestampValue !== undefined) converted.timestampValue = firestoreProtoTimestamp(value.timestampValue);
|
|
1501
1514
|
if (value.mapValue !== undefined) converted.mapValue = { fields: firestoreProtoFields(value.mapValue.fields) };
|
|
1502
1515
|
if (value.arrayValue !== undefined) {
|
|
@@ -1507,6 +1520,14 @@ function firestoreProtoFields(fields) {
|
|
|
1507
1520
|
}
|
|
1508
1521
|
|
|
1509
1522
|
function writtenFirestoreEvent(event) {
|
|
1523
|
+
if (event.datacontenttype === "application/protobuf") {
|
|
1524
|
+
// A single character repetition avoids stack growth; require the absolute end, including no trailing newline.
|
|
1525
|
+
if (typeof event.data !== "string" || event.data.length % 4 !== 0 ||
|
|
1526
|
+
!/^[A-Za-z0-9+/]*={0,2}(?![\s\S])/.test(event.data)) {
|
|
1527
|
+
throw new Error("Firestore protobuf IPC data must be base64 text");
|
|
1528
|
+
}
|
|
1529
|
+
return { ...event, data: Buffer.from(event.data, "base64") };
|
|
1530
|
+
}
|
|
1510
1531
|
if (!["google.cloud.firestore.document.v1.written", "google.cloud.firestore.document.v1.written.withAuthContext"].includes(event.type) ||
|
|
1511
1532
|
!event.datacontenttype?.includes("application/json")) return event;
|
|
1512
1533
|
// The SDK's protobuf decoder derives missing snapshot paths from typed metadata,
|
|
@@ -1538,7 +1559,7 @@ async function invoke(functions, manifest, msg) {
|
|
|
1538
1559
|
throw new Error("entry point does not match the function manifest");
|
|
1539
1560
|
}
|
|
1540
1561
|
if (msg.trigger !== spec.trigger?.type ||
|
|
1541
|
-
!["schedule", "database", "firestore", "storage", "pubsub", "eventarc", "auth"].includes(msg.trigger)) {
|
|
1562
|
+
!["schedule", "database", "firestore", "storage", "pubsub", "eventarc", "auth", "remoteConfig"].includes(msg.trigger)) {
|
|
1542
1563
|
throw new Error("trigger does not match the function manifest");
|
|
1543
1564
|
}
|
|
1544
1565
|
const fn = functions.get(spec.entryPoint);
|
|
@@ -1581,6 +1602,7 @@ async function invoke(functions, manifest, msg) {
|
|
|
1581
1602
|
case "storage":
|
|
1582
1603
|
await fn({ ...msg.event, data: storageObjectInRecordedOrder(msg.event.data) });
|
|
1583
1604
|
return;
|
|
1605
|
+
case "remoteConfig":
|
|
1584
1606
|
case "pubsub":
|
|
1585
1607
|
await fn(msg.event);
|
|
1586
1608
|
return;
|
|
@@ -7,6 +7,7 @@ dict (`firestore_fn.py:108-131`). The adapter therefore builds the production fo
|
|
|
7
7
|
(`functions_framework/__init__.py:174-188`).
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
import base64
|
|
10
11
|
import json
|
|
11
12
|
import os
|
|
12
13
|
import re
|
|
@@ -167,6 +168,13 @@ def firestore_request(event: dict, raw_data: str | None = None) -> Delivery:
|
|
|
167
168
|
if is_strict():
|
|
168
169
|
headers.setdefault("ce-dataschema", _FIRESTORE_DATASCHEMA)
|
|
169
170
|
data = event.get("data")
|
|
171
|
+
if event.get("datacontenttype") == "application/protobuf":
|
|
172
|
+
# Binary IPC data is base64; preserve Rust's protobuf bytes for the real SDK.
|
|
173
|
+
if not isinstance(data, str):
|
|
174
|
+
raise ValueError("Firestore protobuf IPC data must be base64 text")
|
|
175
|
+
body = base64.b64decode(data, validate=True)
|
|
176
|
+
headers["content-type"] = "application/protobuf"
|
|
177
|
+
return Delivery(headers, body, body)
|
|
170
178
|
message = firestore_events.DocumentEventData.from_json(json.dumps(data if isinstance(data, dict) else {}))
|
|
171
179
|
headers["content-type"] = "application/protobuf"
|
|
172
180
|
body = firestore_events.DocumentEventData.serialize(message)
|