@fireemu/darwin-arm64 0.10.0 → 0.11.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 +0 -0
- package/bin/runner-node/index.mjs +68 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @fireemu/darwin-arm64
|
|
2
2
|
|
|
3
3
|
The [fireemu](https://www.npmjs.com/package/fireemu) daemon built for `darwin-arm64`
|
|
4
|
-
(Rust target `aarch64-apple-darwin`), version 0.
|
|
4
|
+
(Rust target `aarch64-apple-darwin`), version 0.11.0.
|
|
5
5
|
|
|
6
6
|
macOS 13 or newer on Apple silicon.
|
|
7
7
|
|
package/bin/fireemu
CHANGED
|
Binary file
|
|
@@ -1056,6 +1056,13 @@ function describe(name, fn, instrumentation) {
|
|
|
1056
1056
|
|
|
1057
1057
|
// v1 functions are called as (data, context) with the legacy event shapes.
|
|
1058
1058
|
|
|
1059
|
+
// An RFC 3339 time with exactly three fractional digits (the extra digits are cut), or the input
|
|
1060
|
+
// unchanged when it is not a time.
|
|
1061
|
+
function millisecondTimestamp(time) {
|
|
1062
|
+
const parsed = new Date(time);
|
|
1063
|
+
return Number.isNaN(parsed.getTime()) ? time : parsed.toISOString();
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1059
1066
|
function v1Context(msg) {
|
|
1060
1067
|
const event = msg.event;
|
|
1061
1068
|
switch (msg.trigger) {
|
|
@@ -1078,7 +1085,11 @@ function v1Context(msg) {
|
|
|
1078
1085
|
eventType: legacy,
|
|
1079
1086
|
// A string: firebase-functions rewrites a legacy event type's resource into
|
|
1080
1087
|
// { service, name } itself (makeCloudFunction); an object here would be nested.
|
|
1081
|
-
resource: event.
|
|
1088
|
+
resource: [event.project, event.database, event.document].every(
|
|
1089
|
+
value => typeof value === "string" && value.length > 0,
|
|
1090
|
+
)
|
|
1091
|
+
? `projects/${event.project}/databases/${event.database}/documents/${event.document}`
|
|
1092
|
+
: event.source,
|
|
1082
1093
|
params: event.params || {},
|
|
1083
1094
|
};
|
|
1084
1095
|
}
|
|
@@ -1086,7 +1097,12 @@ function v1Context(msg) {
|
|
|
1086
1097
|
const o = event.data;
|
|
1087
1098
|
return {
|
|
1088
1099
|
eventId: event.id,
|
|
1089
|
-
timestamp
|
|
1100
|
+
// Production hands a 1st gen Storage handler a timestamp with exactly three fractional
|
|
1101
|
+
// digits (observed 2026-10-01: `2026-10-01T08:49:26.577Z`, after the object's
|
|
1102
|
+
// `timeCreated` of `.486Z`). The runtime admits the event later than it creates the
|
|
1103
|
+
// object, so the timestamp is cut from the admission instant the frame carries; the
|
|
1104
|
+
// CloudEvent time of a finalize event is the creation instant.
|
|
1105
|
+
timestamp: millisecondTimestamp(msg.admittedAt ?? event.time),
|
|
1090
1106
|
eventType: {
|
|
1091
1107
|
"google.cloud.storage.object.v1.finalized": "google.storage.object.finalize",
|
|
1092
1108
|
"google.cloud.storage.object.v1.deleted": "google.storage.object.delete",
|
|
@@ -1346,6 +1362,54 @@ async function makeHttpServer(functions, manifest) {
|
|
|
1346
1362
|
});
|
|
1347
1363
|
}
|
|
1348
1364
|
|
|
1365
|
+
let writtenFirestoreCodec;
|
|
1366
|
+
|
|
1367
|
+
function firestoreProtoTimestamp(value) {
|
|
1368
|
+
if (typeof value !== "string") return value;
|
|
1369
|
+
const match = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,9}))?(Z|[+-]\d{2}:\d{2})$/.exec(value);
|
|
1370
|
+
if (!match) throw new Error("invalid Firestore protobuf timestamp");
|
|
1371
|
+
const milliseconds = Date.parse(`${match[1]}${match[3]}`);
|
|
1372
|
+
if (!Number.isFinite(milliseconds)) throw new Error("invalid Firestore protobuf timestamp");
|
|
1373
|
+
return { seconds: Math.floor(milliseconds / 1000), nanos: Number((match[2] ?? "").padEnd(9, "0")) };
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
function firestoreProtoFields(fields) {
|
|
1377
|
+
return Object.fromEntries(Object.entries(fields ?? {}).map(([key, value]) => {
|
|
1378
|
+
const converted = { ...value };
|
|
1379
|
+
if (value.timestampValue !== undefined) converted.timestampValue = firestoreProtoTimestamp(value.timestampValue);
|
|
1380
|
+
if (value.mapValue !== undefined) converted.mapValue = { fields: firestoreProtoFields(value.mapValue.fields) };
|
|
1381
|
+
if (value.arrayValue !== undefined) {
|
|
1382
|
+
converted.arrayValue = { values: (value.arrayValue.values ?? []).map(item => firestoreProtoFields({ item }).item) };
|
|
1383
|
+
}
|
|
1384
|
+
return [key, converted];
|
|
1385
|
+
}));
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
function writtenFirestoreEvent(event) {
|
|
1389
|
+
if (!["google.cloud.firestore.document.v1.written", "google.cloud.firestore.document.v1.written.withAuthContext"].includes(event.type) ||
|
|
1390
|
+
!event.datacontenttype?.includes("application/json")) return event;
|
|
1391
|
+
// The SDK's protobuf decoder derives missing snapshot paths from typed metadata,
|
|
1392
|
+
// independently of the canonical database source. Reuse the codebase's shipped codec.
|
|
1393
|
+
if (!writtenFirestoreCodec) {
|
|
1394
|
+
const require = createRequire(join(sourceDir, "package.json"));
|
|
1395
|
+
const { root } = firebaseFunctionsPackage(require);
|
|
1396
|
+
writtenFirestoreCodec = require(join(root, "protos/compiledFirestore.js")).google.events.cloud.firestore.v1.DocumentEventData;
|
|
1397
|
+
}
|
|
1398
|
+
const data = { ...event.data };
|
|
1399
|
+
for (const side of ["value", "oldValue"]) {
|
|
1400
|
+
if (data[side] === undefined || data[side] === null) continue;
|
|
1401
|
+
const document = { ...data[side], fields: firestoreProtoFields(data[side].fields) };
|
|
1402
|
+
for (const time of ["createTime", "updateTime"]) {
|
|
1403
|
+
if (document[time] !== undefined) document[time] = firestoreProtoTimestamp(document[time]);
|
|
1404
|
+
}
|
|
1405
|
+
data[side] = document;
|
|
1406
|
+
}
|
|
1407
|
+
const message = writtenFirestoreCodec.fromObject(data);
|
|
1408
|
+
const invalid = writtenFirestoreCodec.verify(message);
|
|
1409
|
+
if (invalid) throw new Error(`invalid Firestore protobuf event: ${invalid}`);
|
|
1410
|
+
return { ...event, datacontenttype: "application/protobuf", data: Buffer.from(writtenFirestoreCodec.encode(message).finish()) };
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1349
1413
|
async function invoke(functions, manifest, msg) {
|
|
1350
1414
|
const spec = manifest.functions.find((f) => f.name === msg.function);
|
|
1351
1415
|
if (!spec) throw new Error("unknown function");
|
|
@@ -1377,6 +1441,8 @@ async function invoke(functions, manifest, msg) {
|
|
|
1377
1441
|
return;
|
|
1378
1442
|
}
|
|
1379
1443
|
case "firestore":
|
|
1444
|
+
await fn(writtenFirestoreEvent(msg.event));
|
|
1445
|
+
return;
|
|
1380
1446
|
case "storage":
|
|
1381
1447
|
case "pubsub":
|
|
1382
1448
|
// A custom event reaches the handler as the CloudEvent itself, exactly as the official
|