run402 3.7.1 → 3.7.3
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/lib/functions.mjs +234 -2
- package/package.json +1 -1
- package/sdk/dist/config.d.ts +10 -1
- package/sdk/dist/config.d.ts.map +1 -1
- package/sdk/dist/config.js +30 -0
- package/sdk/dist/config.js.map +1 -1
- package/sdk/dist/index.d.ts +6 -1
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +14 -1
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +115 -15
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +21 -2
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.types.js.map +1 -1
- package/sdk/dist/namespaces/functions.d.ts +25 -1
- package/sdk/dist/namespaces/functions.d.ts.map +1 -1
- package/sdk/dist/namespaces/functions.js +272 -2
- package/sdk/dist/namespaces/functions.js.map +1 -1
- package/sdk/dist/namespaces/functions.types.d.ts +87 -1
- package/sdk/dist/namespaces/functions.types.d.ts.map +1 -1
- package/sdk/dist/node/config.d.ts +2 -2
- package/sdk/dist/node/config.d.ts.map +1 -1
- package/sdk/dist/node/config.js +1 -1
- package/sdk/dist/node/config.js.map +1 -1
- package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +3 -0
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
- package/sdk/dist/node/index.d.ts +2 -2
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +1 -1
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/scoped.d.ts +14 -1
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +31 -0
- package/sdk/dist/scoped.js.map +1 -1
|
@@ -718,6 +718,7 @@ function functionToCoreSpec(fn) {
|
|
|
718
718
|
...(fn.entrypoint !== undefined ? { entrypoint: fn.entrypoint } : {}),
|
|
719
719
|
...(fn.config !== undefined ? { config: fn.config } : {}),
|
|
720
720
|
...(fn.deps !== undefined ? { deps: fn.deps } : {}),
|
|
721
|
+
...(fn.triggers !== undefined ? { triggers: fn.triggers } : {}),
|
|
721
722
|
...(fn.schedule !== undefined ? { schedule: fn.schedule } : {}),
|
|
722
723
|
...(fn.requireAuth !== undefined ? { requireAuth: fn.requireAuth } : {}),
|
|
723
724
|
...(fn.requireRole !== undefined ? { requireRole: fn.requireRole } : {}),
|
|
@@ -740,6 +741,7 @@ function functionToWire(fn) {
|
|
|
740
741
|
}
|
|
741
742
|
: {}),
|
|
742
743
|
...(fn.deps !== undefined ? { deps: fn.deps } : {}),
|
|
744
|
+
...(fn.triggers !== undefined ? { triggers: fn.triggers } : {}),
|
|
743
745
|
...(fn.schedule !== undefined ? { schedule: fn.schedule } : {}),
|
|
744
746
|
...(fn.requireAuth !== undefined ? { require_auth: fn.requireAuth } : {}),
|
|
745
747
|
...(fn.requireRole !== undefined
|
|
@@ -1016,11 +1018,14 @@ async function preflightTierFunctionLimits(client, spec, ciCredentials) {
|
|
|
1016
1018
|
max_function_memory_mb: limits.maxMemoryMb.value,
|
|
1017
1019
|
});
|
|
1018
1020
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
+
for (const trigger of scheduleTriggersForFunction(entry.fn)) {
|
|
1022
|
+
if (!limits.minCronIntervalMinutes)
|
|
1023
|
+
continue;
|
|
1024
|
+
const intervalMinutes = estimateCronMinimumIntervalMinutes(trigger.cron);
|
|
1021
1025
|
if (intervalMinutes !== null &&
|
|
1022
1026
|
intervalMinutes < limits.minCronIntervalMinutes.value) {
|
|
1023
|
-
|
|
1027
|
+
const triggerLabel = trigger.id === "__legacy__" ? "schedule" : `trigger ${trigger.id}`;
|
|
1028
|
+
throw tierLimitError(`Function ${entry.name} ${triggerLabel} runs every ${intervalMinutes} minute(s), below the ${limits.tier} tier minimum interval of ${limits.minCronIntervalMinutes.value} minutes.`, `${entry.fieldPrefix}.${trigger.fieldSuffix}`, trigger.cron, limits, limits.minCronIntervalMinutes, {
|
|
1024
1029
|
interval_minutes: intervalMinutes,
|
|
1025
1030
|
min_interval_minutes: limits.minCronIntervalMinutes.value,
|
|
1026
1031
|
min_cron_interval_minutes: limits.minCronIntervalMinutes.value,
|
|
@@ -1044,7 +1049,7 @@ function hasFunctionTierPreflightInputs(functions) {
|
|
|
1044
1049
|
return false;
|
|
1045
1050
|
return collectFunctionPreflightEntries(functions).some((entry) => (entry.fn.config?.timeoutSeconds !== undefined ||
|
|
1046
1051
|
entry.fn.config?.memoryMb !== undefined ||
|
|
1047
|
-
|
|
1052
|
+
scheduleTriggersForFunction(entry.fn).length > 0));
|
|
1048
1053
|
}
|
|
1049
1054
|
function collectFunctionPreflightEntries(functions) {
|
|
1050
1055
|
if (!functions)
|
|
@@ -1160,23 +1165,21 @@ async function computeDesiredScheduledFunctionCount(client, spec) {
|
|
|
1160
1165
|
function countScheduledFunctionsInSetEntries(functions) {
|
|
1161
1166
|
if (!functions)
|
|
1162
1167
|
return 0;
|
|
1163
|
-
|
|
1164
|
-
for (const
|
|
1165
|
-
|
|
1166
|
-
names.add(name);
|
|
1168
|
+
let count = 0;
|
|
1169
|
+
for (const fn of Object.values(functions.replace ?? {})) {
|
|
1170
|
+
count += scheduleTriggersForFunction(fn).length;
|
|
1167
1171
|
}
|
|
1168
|
-
for (const
|
|
1169
|
-
|
|
1170
|
-
names.add(name);
|
|
1172
|
+
for (const fn of Object.values(functions.patch?.set ?? {})) {
|
|
1173
|
+
count += scheduleTriggersForFunction(fn).length;
|
|
1171
1174
|
}
|
|
1172
|
-
return
|
|
1175
|
+
return count;
|
|
1173
1176
|
}
|
|
1174
1177
|
function scheduledFunctionNames(functions) {
|
|
1175
1178
|
if (!functions)
|
|
1176
1179
|
return null;
|
|
1177
1180
|
const scheduled = new Set();
|
|
1178
1181
|
for (const [name, fn] of Object.entries(functions)) {
|
|
1179
|
-
if (
|
|
1182
|
+
if (scheduleTriggersForFunction(fn).length > 0)
|
|
1180
1183
|
scheduled.add(name);
|
|
1181
1184
|
}
|
|
1182
1185
|
return scheduled;
|
|
@@ -1188,7 +1191,7 @@ function applyScheduledFunctionPatch(scheduled, patch) {
|
|
|
1188
1191
|
for (const [name, fn] of Object.entries(patch?.set ?? {})) {
|
|
1189
1192
|
if (fn.schedule === null)
|
|
1190
1193
|
scheduled.delete(name);
|
|
1191
|
-
else if (
|
|
1194
|
+
else if (scheduleTriggersForFunction(fn).length > 0)
|
|
1192
1195
|
scheduled.add(name);
|
|
1193
1196
|
}
|
|
1194
1197
|
}
|
|
@@ -1205,11 +1208,33 @@ async function readActiveScheduledFunctionNames(client, projectId) {
|
|
|
1205
1208
|
}
|
|
1206
1209
|
const scheduled = new Set();
|
|
1207
1210
|
for (const fn of inventory.functions ?? []) {
|
|
1208
|
-
if (isScheduledCron(fn.schedule))
|
|
1211
|
+
if (isScheduledCron(fn.schedule) || scheduleTriggersForFunction(fn).length > 0)
|
|
1209
1212
|
scheduled.add(fn.name);
|
|
1210
1213
|
}
|
|
1211
1214
|
return scheduled;
|
|
1212
1215
|
}
|
|
1216
|
+
function scheduleTriggersForFunction(fn) {
|
|
1217
|
+
if (fn.triggers && fn.triggers.length > 0) {
|
|
1218
|
+
return fn.triggers
|
|
1219
|
+
.filter((trigger) => trigger.type === "schedule")
|
|
1220
|
+
.map((trigger) => ({
|
|
1221
|
+
...trigger,
|
|
1222
|
+
fieldSuffix: `triggers.${trigger.id}.cron`,
|
|
1223
|
+
}));
|
|
1224
|
+
}
|
|
1225
|
+
return isScheduledCron(fn.schedule)
|
|
1226
|
+
? [{
|
|
1227
|
+
id: "__legacy__",
|
|
1228
|
+
type: "schedule",
|
|
1229
|
+
cron: fn.schedule,
|
|
1230
|
+
timezone: "UTC",
|
|
1231
|
+
misfire_policy: "skip",
|
|
1232
|
+
overlap_policy: "allow",
|
|
1233
|
+
run: { event_type: "legacy.schedule", payload: {} },
|
|
1234
|
+
fieldSuffix: "schedule",
|
|
1235
|
+
}]
|
|
1236
|
+
: [];
|
|
1237
|
+
}
|
|
1213
1238
|
function scheduledCountTierLimitError(count, limits, limit, countSource) {
|
|
1214
1239
|
return tierLimitError(`Deploy would have ${count} scheduled function(s), exceeding the ${limits.tier} tier maximum of ${limit.value}.`, "functions.scheduled_count", count, limits, limit, {
|
|
1215
1240
|
tier_max: limit.value,
|
|
@@ -1890,6 +1915,7 @@ const FUNCTION_SPEC_FIELDS = new Set([
|
|
|
1890
1915
|
"entrypoint",
|
|
1891
1916
|
"config",
|
|
1892
1917
|
"deps",
|
|
1918
|
+
"triggers",
|
|
1893
1919
|
"schedule",
|
|
1894
1920
|
"requireAuth",
|
|
1895
1921
|
"requireRole",
|
|
@@ -1897,6 +1923,8 @@ const FUNCTION_SPEC_FIELDS = new Set([
|
|
|
1897
1923
|
"capabilities",
|
|
1898
1924
|
]);
|
|
1899
1925
|
const FUNCTION_CONFIG_FIELDS = new Set(["timeoutSeconds", "memoryMb"]);
|
|
1926
|
+
const FUNCTION_TRIGGER_FIELDS = new Set(["id", "type", "cron", "timezone", "misfire_policy", "overlap_policy", "run"]);
|
|
1927
|
+
const FUNCTION_TRIGGER_RUN_FIELDS = new Set(["event_type", "payload", "retry", "expires_after_seconds"]);
|
|
1900
1928
|
const SITE_SPEC_FIELDS = new Set(["replace", "patch", "public_paths"]);
|
|
1901
1929
|
const SITE_PATCH_FIELDS = new Set(["put", "delete"]);
|
|
1902
1930
|
const SITE_PUBLIC_PATHS_FIELDS = new Set(["mode", "replace"]);
|
|
@@ -2029,6 +2057,56 @@ function validateFunctionMap(value, resource) {
|
|
|
2029
2057
|
if (entry.files !== undefined) {
|
|
2030
2058
|
requireObject(entry.files, `${resource}.${name}.files`);
|
|
2031
2059
|
}
|
|
2060
|
+
validateFunctionTriggers(entry.triggers, `${resource}.${name}.triggers`);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
function validateFunctionTriggers(value, resource) {
|
|
2064
|
+
if (value === undefined)
|
|
2065
|
+
return;
|
|
2066
|
+
if (!Array.isArray(value))
|
|
2067
|
+
throw invalidSpec(`ReleaseSpec.${resource} must be an array`, resource);
|
|
2068
|
+
const seen = new Set();
|
|
2069
|
+
for (const [index, trigger] of value.entries()) {
|
|
2070
|
+
const path = `${resource}.${index}`;
|
|
2071
|
+
const obj = requireObject(trigger, path);
|
|
2072
|
+
validateKnownFields(obj, path, FUNCTION_TRIGGER_FIELDS, {
|
|
2073
|
+
delivery: "Remove delivery; schedule triggers always start durable function runs.",
|
|
2074
|
+
});
|
|
2075
|
+
if (typeof obj.id !== "string" || obj.id.trim() === "") {
|
|
2076
|
+
throw invalidSpec(`ReleaseSpec.${path}.id is required for schedule triggers`, `${path}.id`);
|
|
2077
|
+
}
|
|
2078
|
+
if (seen.has(obj.id))
|
|
2079
|
+
throw invalidSpec(`ReleaseSpec.${path}.id duplicates ${JSON.stringify(obj.id)}`, `${path}.id`);
|
|
2080
|
+
seen.add(obj.id);
|
|
2081
|
+
if (obj.type !== "schedule")
|
|
2082
|
+
throw invalidSpec(`ReleaseSpec.${path}.type must be "schedule"`, `${path}.type`);
|
|
2083
|
+
if (typeof obj.cron !== "string" || obj.cron.trim().split(/\s+/).length !== 5) {
|
|
2084
|
+
throw invalidSpec(`ReleaseSpec.${path}.cron must be a 5-field cron expression`, `${path}.cron`);
|
|
2085
|
+
}
|
|
2086
|
+
if (obj.timezone !== undefined && typeof obj.timezone !== "string") {
|
|
2087
|
+
throw invalidSpec(`ReleaseSpec.${path}.timezone must be a string`, `${path}.timezone`);
|
|
2088
|
+
}
|
|
2089
|
+
if (obj.misfire_policy !== undefined && obj.misfire_policy !== "skip") {
|
|
2090
|
+
throw invalidSpec(`ReleaseSpec.${path}.misfire_policy must be "skip"`, `${path}.misfire_policy`);
|
|
2091
|
+
}
|
|
2092
|
+
if (obj.overlap_policy !== undefined && obj.overlap_policy !== "allow") {
|
|
2093
|
+
throw invalidSpec(`ReleaseSpec.${path}.overlap_policy must be "allow"`, `${path}.overlap_policy`);
|
|
2094
|
+
}
|
|
2095
|
+
const run = requireObject(obj.run, `${path}.run`);
|
|
2096
|
+
validateKnownFields(run, `${path}.run`, FUNCTION_TRIGGER_RUN_FIELDS);
|
|
2097
|
+
if (typeof run.event_type !== "string" || run.event_type.trim() === "") {
|
|
2098
|
+
throw invalidSpec(`ReleaseSpec.${path}.run.event_type is required`, `${path}.run.event_type`);
|
|
2099
|
+
}
|
|
2100
|
+
if (run.payload !== undefined)
|
|
2101
|
+
requireObject(run.payload, `${path}.run.payload`);
|
|
2102
|
+
if (run.retry !== undefined)
|
|
2103
|
+
requireObject(run.retry, `${path}.run.retry`);
|
|
2104
|
+
if (run.expires_after_seconds !== undefined &&
|
|
2105
|
+
(typeof run.expires_after_seconds !== "number" ||
|
|
2106
|
+
!Number.isSafeInteger(run.expires_after_seconds) ||
|
|
2107
|
+
run.expires_after_seconds <= 0)) {
|
|
2108
|
+
throw invalidSpec(`ReleaseSpec.${path}.run.expires_after_seconds must be a positive integer`, `${path}.run.expires_after_seconds`);
|
|
2109
|
+
}
|
|
2032
2110
|
}
|
|
2033
2111
|
}
|
|
2034
2112
|
/**
|
|
@@ -2934,6 +3012,8 @@ async function normalizeFunction(fn, remember) {
|
|
|
2934
3012
|
out.config = fn.config;
|
|
2935
3013
|
if (fn.deps !== undefined)
|
|
2936
3014
|
out.deps = fn.deps;
|
|
3015
|
+
if (fn.triggers !== undefined)
|
|
3016
|
+
out.triggers = normalizeFunctionTriggers(fn.triggers);
|
|
2937
3017
|
if (fn.schedule !== undefined)
|
|
2938
3018
|
out.schedule = fn.schedule;
|
|
2939
3019
|
if (fn.entrypoint)
|
|
@@ -2955,6 +3035,26 @@ async function normalizeFunction(fn, remember) {
|
|
|
2955
3035
|
}
|
|
2956
3036
|
return out;
|
|
2957
3037
|
}
|
|
3038
|
+
function normalizeFunctionTriggers(triggers) {
|
|
3039
|
+
return triggers
|
|
3040
|
+
.map((trigger) => ({
|
|
3041
|
+
id: trigger.id,
|
|
3042
|
+
type: "schedule",
|
|
3043
|
+
cron: trigger.cron,
|
|
3044
|
+
timezone: trigger.timezone ?? "UTC",
|
|
3045
|
+
misfire_policy: trigger.misfire_policy ?? "skip",
|
|
3046
|
+
overlap_policy: trigger.overlap_policy ?? "allow",
|
|
3047
|
+
run: {
|
|
3048
|
+
event_type: trigger.run.event_type,
|
|
3049
|
+
payload: trigger.run.payload ?? {},
|
|
3050
|
+
...(trigger.run.retry !== undefined ? { retry: { ...trigger.run.retry } } : {}),
|
|
3051
|
+
...(trigger.run.expires_after_seconds !== undefined
|
|
3052
|
+
? { expires_after_seconds: trigger.run.expires_after_seconds }
|
|
3053
|
+
: {}),
|
|
3054
|
+
},
|
|
3055
|
+
}))
|
|
3056
|
+
.sort((a, b) => a.id.localeCompare(b.id));
|
|
3057
|
+
}
|
|
2958
3058
|
async function normalizeFileSet(set, remember) {
|
|
2959
3059
|
// `dir(path)` produces a LocalDirRef sentinel that is documented as a
|
|
2960
3060
|
// valid site.replace / site.patch.put input. Expand it to a plain FileSet
|