@fedify/netlify 2.4.0-pr.934.40 → 2.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  <!-- deno-fmt-ignore-file -->
2
2
 
3
- @fedify/netlify: Run Fedify queues with Netlify Async Workloads
4
- ===============================================================
3
+ @fedify/netlify: Run Fedify with Netlify blobs and async workloads
4
+ ==================================================================
5
5
 
6
6
  [![JSR][JSR badge]][JSR]
7
7
  [![npm][npm badge]][npm]
@@ -9,10 +9,11 @@
9
9
 
10
10
  *This package is available since Fedify 2.4.0.*
11
11
 
12
- This package connects [Fedify]'s [`MessageQueue`] API to
13
- [Netlify Async Workloads]. `NetlifyMessageQueue` publishes durable events,
14
- while `createNetlifyQueueHandler()` turns a Netlify Function into their
15
- consumer.
12
+ This package connects [Fedify]'s [`KvStore`] and [`MessageQueue`] APIs to
13
+ Netlify. `NetlifyBlobsKvStore` stores federation state in [Netlify Blobs],
14
+ `NetlifyMessageQueue` publishes durable events through
15
+ [Netlify Async Workloads], and `createNetlifyQueueHandler()` turns a Netlify
16
+ Function into their consumer.
16
17
 
17
18
  The initial release targets Netlify Functions, not Netlify Edge Functions.
18
19
 
@@ -23,13 +24,17 @@ The initial release targets Netlify Functions, not Netlify Edge Functions.
23
24
  [@fedify@hackers.pub badge]: https://fedi-badge.minhee.org/@fedify@hackers.pub/followers.svg
24
25
  [@fedify@hackers.pub]: https://hackers.pub/@fedify
25
26
  [Fedify]: https://fedify.dev/
27
+ [`KvStore`]: https://jsr.io/@fedify/fedify/doc/federation/~/KvStore
26
28
  [`MessageQueue`]: https://jsr.io/@fedify/fedify/doc/federation/~/MessageQueue
29
+ [Netlify Blobs]: https://docs.netlify.com/build/data-and-storage/netlify-blobs/
27
30
  [Netlify Async Workloads]: https://docs.netlify.com/build/async-workloads/get-started/
28
31
 
29
32
 
30
33
  Installation
31
34
  ------------
32
35
 
36
+ For queue-only usage, install the package with Netlify Async Workloads:
37
+
33
38
  ~~~~ sh
34
39
  deno add jsr:@fedify/netlify npm:@netlify/async-workloads # Deno
35
40
  npm add @fedify/netlify @netlify/async-workloads # npm
@@ -38,8 +43,62 @@ yarn add @fedify/netlify @netlify/async-workloads # Yarn
38
43
  bun add @fedify/netlify @netlify/async-workloads # Bun
39
44
  ~~~~
40
45
 
41
- The PostgreSQL-backed `orderingKv` example below also needs
42
- `@fedify/postgres`, `@netlify/database`, and `postgres`:
46
+
47
+ Usage
48
+ -----
49
+
50
+ To use `NetlifyBlobsKvStore`, also install Netlify Blobs:
51
+
52
+ ~~~~ sh
53
+ deno add npm:@netlify/blobs # Deno
54
+ npm add @netlify/blobs # npm
55
+ pnpm add @netlify/blobs # pnpm
56
+ yarn add @netlify/blobs # Yarn
57
+ bun add @netlify/blobs # Bun
58
+ ~~~~
59
+
60
+ Create one store and queue for both the web application and the workload
61
+ function. `NetlifyBlobsKvStore` provides the compare-and-set (CAS) support
62
+ required when Fedify emits messages with an `orderingKey`, without requiring a
63
+ separate database:
64
+
65
+ ~~~~ typescript
66
+ import { AsyncWorkloadsClient } from "@netlify/async-workloads";
67
+ import { getStore } from "@netlify/blobs";
68
+ import {
69
+ NetlifyBlobsKvStore,
70
+ NetlifyMessageQueue,
71
+ } from "@fedify/netlify";
72
+
73
+ export const kv = new NetlifyBlobsKvStore(getStore({
74
+ name: "fedify",
75
+ consistency: "strong",
76
+ }));
77
+ export const queue = new NetlifyMessageQueue({
78
+ client: new AsyncWorkloadsClient(),
79
+ orderingKv: kv,
80
+ });
81
+ ~~~~
82
+
83
+ CAS operations always use strong reads and conditional writes. The
84
+ `consistency: "strong"` setting above also gives ordinary `get()` calls and
85
+ listings strong consistency. You can omit it when lower-latency, eventually
86
+ consistent ordinary reads are acceptable.
87
+
88
+ TTL expiration is logical: expired blobs remain in Netlify Blobs but are
89
+ hidden by `get()` and `list()`. CAS deletion similarly writes a tombstone so
90
+ that a concurrent writer cannot recreate the key undetected. Tombstones are
91
+ also hidden and can be replaced by a later CAS operation, but they are not
92
+ removed automatically. Use a dedicated Netlify Blobs store and account for
93
+ these retained blobs. Only remove them during maintenance when concurrent CAS
94
+ operations for those keys have stopped; physical deletion during a race would
95
+ remove the version token that protects the key.
96
+
97
+ ### PostgreSQL alternative
98
+
99
+ If the application already uses PostgreSQL, `PostgresKvStore` can provide the
100
+ same CAS-capable ordering storage. Install `@fedify/postgres`,
101
+ `@netlify/database`, and `postgres` in addition to the base dependencies:
43
102
 
44
103
  ~~~~ sh
45
104
  deno add jsr:@fedify/postgres npm:@netlify/database npm:postgres # Deno
@@ -49,29 +108,20 @@ yarn add @fedify/postgres @netlify/database postgres # Yarn
49
108
  bun add @fedify/postgres @netlify/database postgres # Bun
50
109
  ~~~~
51
110
 
52
-
53
- Usage
54
- -----
55
-
56
- Create one queue for both the web application and the workload function. A
57
- CAS-capable `KvStore`, such as `PostgresKvStore`, is required if Fedify emits
58
- messages with an `orderingKey`:
111
+ Then replace the `kv` declaration from the main example:
59
112
 
60
113
  ~~~~ typescript
61
- import { AsyncWorkloadsClient } from "@netlify/async-workloads";
62
114
  import { getConnectionString } from "@netlify/database";
63
- import { NetlifyMessageQueue } from "@fedify/netlify";
64
115
  import { PostgresKvStore } from "@fedify/postgres";
65
116
  import postgres from "postgres";
66
117
 
67
118
  const sql = postgres(getConnectionString());
68
119
  export const kv = new PostgresKvStore(sql);
69
- export const queue = new NetlifyMessageQueue({
70
- client: new AsyncWorkloadsClient(),
71
- orderingKv: kv,
72
- });
73
120
  ~~~~
74
121
 
122
+ Ordering state must use crash-safe storage. `PostgresKvStore` creates a logged
123
+ table by default; do not pass `unlogged: true` for `orderingKv`.
124
+
75
125
  Pass the queue to Fedify with `manuallyStartQueue: true`. Async Workloads
76
126
  invokes the consumer, so `NetlifyMessageQueue.listen()` is intentionally not
77
127
  available:
@@ -142,9 +192,6 @@ because a lost response does not prove that the router rejected the event.
142
192
  Use the error's `orderingKey` and `orderingSequence` for manual recovery only
143
193
  after ruling out delivery.
144
194
 
145
- Ordering state must use crash-safe storage. `PostgresKvStore` creates a logged
146
- table by default; do not pass `unlogged: true` for `orderingKv`.
147
-
148
195
  Netlify limits an event payload to 500 KB. Fedify messages, including any
149
196
  embedded activity, must remain below that limit.
150
197
 
@@ -156,7 +203,7 @@ Fedify rejects a multi-message `enqueueTaskMany()` call with one
156
203
  batch enqueue so a failed partial send cannot produce duplicates on retry.
157
204
 
158
205
  See the [deployment manual] and the [Netlify Astro example] for a complete
159
- setup with Netlify Database.
206
+ setup using the PostgreSQL alternative with Netlify Database.
160
207
 
161
208
  [deployment manual]: https://fedify.dev/manual/deploy#netlify-functions
162
209
  [Netlify Astro example]: https://github.com/fedify-dev/fedify/tree/main/examples/netlify-astro
package/dist/mod.cjs CHANGED
@@ -1,6 +1,8 @@
1
1
 
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  let _netlify_async_workloads = require("@netlify/async-workloads");
4
+ let byte_encodings_base64url = require("byte-encodings/base64url");
5
+ let es_toolkit = require("es-toolkit");
4
6
  //#region ../../node_modules/.pnpm/temporal-polyfill@1.0.1/node_modules/temporal-polyfill/chunks/root.js
5
7
  const NativeTemporal = globalThis.Temporal;
6
8
  //#endregion
@@ -152,7 +154,7 @@ function parseInt0(s) {
152
154
  function padNumber(digits, num) {
153
155
  return String(num).padStart(digits, "0");
154
156
  }
155
- const padNumber2 = /* @__PURE__ */ bindArgs(padNumber, 2);
157
+ const padNumber2 = /*@__PURE__*/ bindArgs(padNumber, 2);
156
158
  function compareNumbers(a, b) {
157
159
  return Math.sign(a - b);
158
160
  }
@@ -220,7 +222,7 @@ const unitNameMap = {
220
222
  month: 8,
221
223
  year: 9
222
224
  };
223
- const unitNamesAsc = /* @__PURE__ */ Object.keys(unitNameMap);
225
+ const unitNamesAsc = /*@__PURE__*/ Object.keys(unitNameMap);
224
226
  const nanoInMicro = nanoInMicro$1;
225
227
  const nanoInMilli = nanoInMilli$1;
226
228
  const nanoInSec = nanoInSec$1;
@@ -236,19 +238,19 @@ const unitNanoMap = [
236
238
  nanoInHour,
237
239
  nanoInUtcDay
238
240
  ];
239
- const bigNanoInMicro = /* @__PURE__ */ BigInt(nanoInMicro);
240
- const bigNanoInMilli = /* @__PURE__ */ BigInt(nanoInMilli);
241
- const bigNanoInSec = /* @__PURE__ */ BigInt(nanoInSec);
242
- const bigNanoInMinute = /* @__PURE__ */ BigInt(nanoInMinute);
243
- const bigNanoInHour = /* @__PURE__ */ BigInt(nanoInHour);
244
- const bigNanoInUtcDay = /* @__PURE__ */ BigInt(nanoInUtcDay);
241
+ const bigNanoInMicro = /*@__PURE__*/ BigInt(nanoInMicro);
242
+ const bigNanoInMilli = /*@__PURE__*/ BigInt(nanoInMilli);
243
+ const bigNanoInSec = /*@__PURE__*/ BigInt(nanoInSec);
244
+ const bigNanoInMinute = /*@__PURE__*/ BigInt(nanoInMinute);
245
+ const bigNanoInHour = /*@__PURE__*/ BigInt(nanoInHour);
246
+ const bigNanoInUtcDay = /*@__PURE__*/ BigInt(nanoInUtcDay);
245
247
  function divideBigNanoToExactNumber(bigNano, divisorNano) {
246
248
  const days = Number(bigNano / bigNanoInUtcDay);
247
249
  const timeNano = Number(bigNano % bigNanoInUtcDay);
248
250
  return days * (nanoInUtcDay / divisorNano) + (Math.trunc(timeNano / divisorNano) + timeNano % divisorNano / divisorNano);
249
251
  }
250
- const timeFieldNamesAsc = /* @__PURE__ */ unitNamesAsc.slice(0, 6);
251
- const timeGetters = /* @__PURE__ */ createPropGetters(timeFieldNamesAsc);
252
+ const timeFieldNamesAsc = /*@__PURE__*/ unitNamesAsc.slice(0, 6);
253
+ const timeGetters = /*@__PURE__*/ createPropGetters(timeFieldNamesAsc);
252
254
  const yearFieldNamesAsc = ["year"];
253
255
  const dayFieldNamesAsc = ["day"];
254
256
  const calendarDateFieldNamesAsc = [
@@ -270,24 +272,24 @@ const monthDayFieldNames = [
270
272
  "month",
271
273
  "monthCode"
272
274
  ];
273
- const timeFieldNamesAlpha = /* @__PURE__ */ sortStrings(timeFieldNamesAsc);
274
- const yearFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(eraYearFieldNames, yearFieldNamesAsc);
275
- const yearMonthFieldNamesAlpha = /* @__PURE__ */ sortStrings(monthFieldNames, yearFieldNamesAsc);
276
- const yearMonthFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(eraYearFieldNames, yearMonthFieldNamesAlpha);
277
- const yearMonthCodeFieldNamesAlpha = /* @__PURE__ */ sortStrings(["monthCode"], yearFieldNamesAsc);
278
- const yearMonthCodeFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(eraYearFieldNames, yearMonthCodeFieldNamesAlpha);
279
- const monthCodeDayFieldNamesAlpha = /* @__PURE__ */ sortStrings(dayFieldNamesAsc, ["monthCode"]);
280
- const dateFieldNamesAlpha = /* @__PURE__ */ sortStrings(dayFieldNamesAsc, yearMonthFieldNamesAlpha);
281
- const dateFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(dayFieldNamesAsc, eraYearFieldNames, yearMonthFieldNamesAlpha);
282
- const dateTimeFieldNamesAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc);
283
- const dateTimeFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc);
284
- const dateTimeAndOffsetFieldNamesAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc, offsetFieldNames);
285
- const dateTimeAndOffsetFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc, offsetFieldNames);
286
- const dateTimeAndZoneFieldNamesAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc, offsetFieldNames, timeZoneFieldNames);
287
- const dateTimeAndZoneFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc, offsetFieldNames, timeZoneFieldNames);
288
- const yearMonthCodeDayFieldNamesAlpha = /* @__PURE__ */ sortStrings(dayFieldNamesAsc, yearMonthCodeFieldNamesAlpha);
289
- const yearMonthCodeDayFieldNamesWithEraAlpha = /* @__PURE__ */ sortStrings(dayFieldNamesAsc, eraYearFieldNames, yearMonthCodeFieldNamesAlpha);
290
- const timeFieldDefaults = /* @__PURE__ */ zipPropsConst(timeFieldNamesAsc, 0);
275
+ const timeFieldNamesAlpha = /*@__PURE__*/ sortStrings(timeFieldNamesAsc);
276
+ const yearFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(eraYearFieldNames, yearFieldNamesAsc);
277
+ const yearMonthFieldNamesAlpha = /*@__PURE__*/ sortStrings(monthFieldNames, yearFieldNamesAsc);
278
+ const yearMonthFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(eraYearFieldNames, yearMonthFieldNamesAlpha);
279
+ const yearMonthCodeFieldNamesAlpha = /*@__PURE__*/ sortStrings(["monthCode"], yearFieldNamesAsc);
280
+ const yearMonthCodeFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(eraYearFieldNames, yearMonthCodeFieldNamesAlpha);
281
+ const monthCodeDayFieldNamesAlpha = /*@__PURE__*/ sortStrings(dayFieldNamesAsc, ["monthCode"]);
282
+ const dateFieldNamesAlpha = /*@__PURE__*/ sortStrings(dayFieldNamesAsc, yearMonthFieldNamesAlpha);
283
+ const dateFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(dayFieldNamesAsc, eraYearFieldNames, yearMonthFieldNamesAlpha);
284
+ const dateTimeFieldNamesAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc);
285
+ const dateTimeFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc);
286
+ const dateTimeAndOffsetFieldNamesAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc, offsetFieldNames);
287
+ const dateTimeAndOffsetFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc, offsetFieldNames);
288
+ const dateTimeAndZoneFieldNamesAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesAlpha, timeFieldNamesAsc, offsetFieldNames, timeZoneFieldNames);
289
+ const dateTimeAndZoneFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(dateFieldNamesWithEraAlpha, timeFieldNamesAsc, offsetFieldNames, timeZoneFieldNames);
290
+ const yearMonthCodeDayFieldNamesAlpha = /*@__PURE__*/ sortStrings(dayFieldNamesAsc, yearMonthCodeFieldNamesAlpha);
291
+ const yearMonthCodeDayFieldNamesWithEraAlpha = /*@__PURE__*/ sortStrings(dayFieldNamesAsc, eraYearFieldNames, yearMonthCodeFieldNamesAlpha);
292
+ const timeFieldDefaults = /*@__PURE__*/ zipPropsConst(timeFieldNamesAsc, 0);
291
293
  function validateTimeFields(timeFields) {
292
294
  return constrainTimeFields(timeFields, 1), timeFields;
293
295
  }
@@ -516,20 +518,20 @@ function computeCalendarWeekOfYear(calendar, isoDate) {
516
518
  function computeCalendarYearOfWeek(calendar, isoDate) {
517
519
  return calendar === void 0 ? computeIsoWeekFields(isoDate).yearOfWeek : void 0;
518
520
  }
519
- const durationFieldNamesAsc = /* @__PURE__ */ unitNamesAsc.map((unitName) => unitName + "s");
520
- const durationGetters = /* @__PURE__ */ createPropGetters(durationFieldNamesAsc);
521
- const durationFieldNamesAlpha = /* @__PURE__ */ sortStrings(durationFieldNamesAsc);
522
- const durationTimeFieldNamesAsc = /* @__PURE__ */ durationFieldNamesAsc.slice(0, 6);
523
- const durationDateFieldNamesAsc = /* @__PURE__ */ durationFieldNamesAsc.slice(6);
524
- const durationCalendarFieldNamesAsc = /* @__PURE__ */ durationDateFieldNamesAsc.slice(1);
525
- const durationFieldIndexes = /* @__PURE__ */ durationFieldNamesAsc.reduce((indexes, fieldName, i) => (indexes[fieldName] = i, indexes), {});
526
- const durationFieldDefaults = /* @__PURE__ */ zipPropsConst(durationFieldNamesAsc, 0);
527
- const durationTimeFieldDefaults = /* @__PURE__ */ zipPropsConst(durationTimeFieldNamesAsc, 0);
528
- const clearDurationFields = /* @__PURE__ */ bindArgs(zeroOutProps, durationFieldNamesAsc);
521
+ const durationFieldNamesAsc = /*@__PURE__*/ unitNamesAsc.map((unitName) => unitName + "s");
522
+ const durationGetters = /*@__PURE__*/ createPropGetters(durationFieldNamesAsc);
523
+ const durationFieldNamesAlpha = /*@__PURE__*/ sortStrings(durationFieldNamesAsc);
524
+ const durationTimeFieldNamesAsc = /*@__PURE__*/ durationFieldNamesAsc.slice(0, 6);
525
+ const durationDateFieldNamesAsc = /*@__PURE__*/ durationFieldNamesAsc.slice(6);
526
+ const durationCalendarFieldNamesAsc = /*@__PURE__*/ durationDateFieldNamesAsc.slice(1);
527
+ const durationFieldIndexes = /*@__PURE__*/ durationFieldNamesAsc.reduce((indexes, fieldName, i) => (indexes[fieldName] = i, indexes), {});
528
+ const durationFieldDefaults = /*@__PURE__*/ zipPropsConst(durationFieldNamesAsc, 0);
529
+ const durationTimeFieldDefaults = /*@__PURE__*/ zipPropsConst(durationTimeFieldNamesAsc, 0);
530
+ const clearDurationFields = /*@__PURE__*/ bindArgs(zeroOutProps, durationFieldNamesAsc);
529
531
  function requirePropDefined(optionName, optionVal) {
530
532
  return optionVal ?? throwRangeError(missingField(optionName)), optionVal;
531
533
  }
532
- const requireString = /* @__PURE__ */ bindArgs(requireType, "string");
534
+ const requireString = /*@__PURE__*/ bindArgs(requireType, "string");
533
535
  function requireType(typeName, arg, entityName = typeName) {
534
536
  return typeof arg !== typeName && throwTypeError(invalidEntity(entityName, arg)), arg;
535
537
  }
@@ -641,17 +643,17 @@ function coerceChoiceOption(optionName, enumNameMap, options, defaultChoice = 0)
641
643
  const enumNum = enumNameMap[enumStr];
642
644
  return void 0 === enumNum && throwRangeError(invalidChoice(optionName, enumStr, enumNameMap)), enumNum;
643
645
  }
644
- const coerceSmallestUnit = /* @__PURE__ */ bindArgs(coerceUnitOption, smallestUnitStr);
645
- const coerceLargestUnit = /* @__PURE__ */ bindArgs(coerceUnitOption, "largestUnit");
646
- const coerceTotalUnit = /* @__PURE__ */ bindArgs(coerceUnitOption, "unit");
647
- const coerceOverflow = /* @__PURE__ */ bindArgs(coerceChoiceOption, "overflow", overflowMap);
648
- const coerceEpochDisambig = /* @__PURE__ */ bindArgs(coerceChoiceOption, "disambiguation", epochDisambigMap);
649
- const coerceOffsetDisambig = /* @__PURE__ */ bindArgs(coerceChoiceOption, "offset", offsetDisambigMap);
650
- const coerceCalendarDisplay = /* @__PURE__ */ bindArgs(coerceChoiceOption, "calendarName", calendarDisplayMap);
651
- const coerceTimeZoneDisplay = /* @__PURE__ */ bindArgs(coerceChoiceOption, "timeZoneName", timeZoneDisplayMap);
652
- const coerceOffsetDisplay = /* @__PURE__ */ bindArgs(coerceChoiceOption, "offset", offsetDisplayMap);
653
- const coerceRoundingMode = /* @__PURE__ */ bindArgs(coerceChoiceOption, "roundingMode", roundingModeMap);
654
- const coerceDirection = /* @__PURE__ */ bindArgs(coerceChoiceOption, "direction", directionMap);
646
+ const coerceSmallestUnit = /*@__PURE__*/ bindArgs(coerceUnitOption, smallestUnitStr);
647
+ const coerceLargestUnit = /*@__PURE__*/ bindArgs(coerceUnitOption, "largestUnit");
648
+ const coerceTotalUnit = /*@__PURE__*/ bindArgs(coerceUnitOption, "unit");
649
+ const coerceOverflow = /*@__PURE__*/ bindArgs(coerceChoiceOption, "overflow", overflowMap);
650
+ const coerceEpochDisambig = /*@__PURE__*/ bindArgs(coerceChoiceOption, "disambiguation", epochDisambigMap);
651
+ const coerceOffsetDisambig = /*@__PURE__*/ bindArgs(coerceChoiceOption, "offset", offsetDisambigMap);
652
+ const coerceCalendarDisplay = /*@__PURE__*/ bindArgs(coerceChoiceOption, "calendarName", calendarDisplayMap);
653
+ const coerceTimeZoneDisplay = /*@__PURE__*/ bindArgs(coerceChoiceOption, "timeZoneName", timeZoneDisplayMap);
654
+ const coerceOffsetDisplay = /*@__PURE__*/ bindArgs(coerceChoiceOption, "offset", offsetDisplayMap);
655
+ const coerceRoundingMode = /*@__PURE__*/ bindArgs(coerceChoiceOption, "roundingMode", roundingModeMap);
656
+ const coerceDirection = /*@__PURE__*/ bindArgs(coerceChoiceOption, "direction", directionMap);
655
657
  function validateRoundingInc(roundingInc, smallestUnit, allowManyLargeUnits, solarMode) {
656
658
  const upUnitNano = solarMode ? nanoInUtcDay : unitNanoMap[smallestUnit + 1];
657
659
  if (upUnitNano) {
@@ -705,8 +707,8 @@ function refineZonedFieldOptions(options, defaultOffsetDisambig = 0) {
705
707
  epochDisambig
706
708
  ];
707
709
  }
708
- const epochNanoMax = /* @__PURE__ */ BigInt(1e8) * bigNanoInUtcDay;
709
- const epochNanoMin = /* @__PURE__ */ BigInt(-1e8) * bigNanoInUtcDay;
710
+ const epochNanoMax = /*@__PURE__*/ BigInt(1e8) * bigNanoInUtcDay;
711
+ const epochNanoMin = /*@__PURE__*/ BigInt(-1e8) * bigNanoInUtcDay;
710
712
  const plainDateEpochNanoMin = epochNanoMin - bigNanoInUtcDay;
711
713
  const isoYearMonthIndexMin = -3261848;
712
714
  function checkIsoYearMonthInBounds(isoDate) {
@@ -977,11 +979,12 @@ function nudgeRelativeDuration(sign, durationFields, endEpochNano, _largestUnit,
977
979
  }
978
980
  function getTimeZoneTransitionEpochNanoseconds(slots, options) {
979
981
  return slots.timeZone.U(slots.epochNanoseconds, ((options) => {
980
- const res = coerceDirection(normalizeOptionsOrString(options, "direction"), 0);
982
+ const normalizedOptions = normalizeOptionsOrString(options, "direction");
983
+ const res = coerceDirection(normalizedOptions, 0);
981
984
  return res || throwRangeError(invalidEntity("direction", res)), res;
982
985
  })(options));
983
986
  }
984
- const zonedEpochSlotsToIso = /* @__PURE__ */ memoize(_zonedEpochSlotsToIso, WeakMap);
987
+ const zonedEpochSlotsToIso = /*@__PURE__*/ memoize(_zonedEpochSlotsToIso, WeakMap);
985
988
  function _zonedEpochSlotsToIso(slots) {
986
989
  const { epochNanoseconds, timeZone } = slots;
987
990
  const offsetNanoseconds = timeZone.C(epochNanoseconds);
@@ -1547,7 +1550,7 @@ function resolveTimeFields(fields, overflow) {
1547
1550
  ...fields
1548
1551
  }), overflow);
1549
1552
  }
1550
- const offsetRegExp = /* @__PURE__ */ createRegExp("([+-])(\\d{2})(?::?(\\d{2})(?::?(\\d{2})(?:[.,](\\d{1,9}))?)?)?");
1553
+ const offsetRegExp = /*@__PURE__*/ createRegExp("([+-])(\\d{2})(?::?(\\d{2})(?::?(\\d{2})(?:[.,](\\d{1,9}))?)?)?");
1551
1554
  function parseOffsetNano(s) {
1552
1555
  const offsetNano = parseOffsetNanoMaybe(s);
1553
1556
  return void 0 === offsetNano && throwRangeError(failedParse(s)), offsetNano;
@@ -1582,13 +1585,13 @@ const dateFieldRefiners = {
1582
1585
  },
1583
1586
  day: toPositiveIntegerWithTruncation
1584
1587
  };
1585
- const timeFieldRefiners = /* @__PURE__ */ zipPropsConst(timeFieldNamesAsc, toIntegerWithTrunc);
1586
- const durationFieldRefiners = /* @__PURE__ */ zipPropsConst(durationFieldNamesAsc, toStrictInteger);
1588
+ const timeFieldRefiners = /*@__PURE__*/ zipPropsConst(timeFieldNamesAsc, toIntegerWithTrunc);
1589
+ const durationFieldRefiners = /*@__PURE__*/ zipPropsConst(durationFieldNamesAsc, toStrictInteger);
1587
1590
  const offsetFieldRefiners = { offset(offsetString) {
1588
1591
  return parseOffsetNano(toStringViaPrimitive(offsetString));
1589
1592
  } };
1590
- const dateTimeFieldRefiners = /* @__PURE__ */ Object.assign({}, dateFieldRefiners, timeFieldRefiners);
1591
- const zonedDateTimeFieldRefiners = /* @__PURE__ */ Object.assign({}, dateTimeFieldRefiners, offsetFieldRefiners);
1593
+ const dateTimeFieldRefiners = /*@__PURE__*/ Object.assign({}, dateFieldRefiners, timeFieldRefiners);
1594
+ const zonedDateTimeFieldRefiners = /*@__PURE__*/ Object.assign({}, dateTimeFieldRefiners, offsetFieldRefiners);
1592
1595
  function readAndRefineBagFields(bag, validFieldNames, fieldRefiners, requiredFieldNames, disallowEmpty = !requiredFieldNames) {
1593
1596
  const res = {};
1594
1597
  let anyMatching = 0;
@@ -1691,7 +1694,9 @@ const timeZonePeriodDaysByName = {
1691
1694
  const minPossibleTransitionSec = -388152e4;
1692
1695
  function refineTimeDisplayTuple(options, maxSmallestUnit = 4) {
1693
1696
  const subsecDigits = coerceFractionalSecondDigits(options);
1694
- return [coerceRoundingMode(options, 4), ...resolveSmallestUnitAndSubsecDigits(validateUnitRange(smallestUnitStr, coerceSmallestUnit(options), 0, maxSmallestUnit), subsecDigits)];
1697
+ const roundingMode = coerceRoundingMode(options, 4);
1698
+ const smallestUnit = coerceSmallestUnit(options);
1699
+ return [roundingMode, ...resolveSmallestUnitAndSubsecDigits(validateUnitRange(smallestUnitStr, smallestUnit, 0, maxSmallestUnit), subsecDigits)];
1695
1700
  }
1696
1701
  function refineDateDisplayOptions(options) {
1697
1702
  return coerceCalendarDisplay(normalizeOptions(options));
@@ -1866,15 +1871,17 @@ function resolveTimeZoneRecord(rawId) {
1866
1871
  kind: "fixed",
1867
1872
  ...offsetRecord
1868
1873
  };
1869
- return queryNamedTimeZoneRecord("UTC" === upperRawId ? "UTC" : ((rawId) => (badCharactersRegExp.test(rawId) && throwRangeError(invalidTimeZone(rawId)), icuRegExp.test(rawId) && throwRangeError("Forbidden ICU TimeZone"), rawId.toLowerCase().split("/").map((part, partI) => (part.length <= 3 || /\d/.test(part)) && !/etc|yap/.test(part) ? part.toUpperCase() : part.replace(/baja|dumont|[a-z]+/g, (a, i) => a.length <= 2 && !partI || "in" === a || "chat" === a ? a.toUpperCase() : a.length > 2 || !i ? capitalize(a).replace(/island|noronha|murdo|rivadavia|urville/, capitalize) : a)).join("/")))(rawId));
1874
+ const normId = "UTC" === upperRawId ? "UTC" : ((rawId) => (badCharactersRegExp.test(rawId) && throwRangeError(invalidTimeZone(rawId)), icuRegExp.test(rawId) && throwRangeError("Forbidden ICU TimeZone"), rawId.toLowerCase().split("/").map((part, partI) => (part.length <= 3 || /\d/.test(part)) && !/etc|yap/.test(part) ? part.toUpperCase() : part.replace(/baja|dumont|[a-z]+/g, (a, i) => a.length <= 2 && !partI || "in" === a || "chat" === a ? a.toUpperCase() : a.length > 2 || !i ? capitalize(a).replace(/island|noronha|murdo|rivadavia|urville/, capitalize) : a)).join("/")))(rawId);
1875
+ return queryNamedTimeZoneRecord(normId);
1870
1876
  }
1871
- const queryNamedTimeZoneRecord = /* @__PURE__ */ memoize((normId) => {
1877
+ const queryNamedTimeZoneRecord = /*@__PURE__*/ memoize((normId) => {
1872
1878
  if ("UTC" === normId) return {
1873
1879
  kind: "utc",
1874
1880
  id: normId,
1875
1881
  o: normId
1876
1882
  };
1877
- const format = queryTimeZoneIntlFormat(normId.toUpperCase());
1883
+ const upperNormId = normId.toUpperCase();
1884
+ const format = queryTimeZoneIntlFormat(upperNormId);
1878
1885
  return {
1879
1886
  kind: "named",
1880
1887
  id: normId,
@@ -1882,7 +1889,7 @@ const queryNamedTimeZoneRecord = /* @__PURE__ */ memoize((normId) => {
1882
1889
  o: format.resolvedOptions().timeZone
1883
1890
  };
1884
1891
  });
1885
- const queryTimeZoneIntlFormat = /* @__PURE__ */ memoize((upperNormId) => new RawDateTimeFormat("en-u-hc-h23", {
1892
+ const queryTimeZoneIntlFormat = /*@__PURE__*/ memoize((upperNormId) => new RawDateTimeFormat("en-u-hc-h23", {
1886
1893
  calendar: "iso8601",
1887
1894
  timeZone: upperNormId,
1888
1895
  era: "short",
@@ -1897,7 +1904,7 @@ function queryTimeZone(rawTimeZoneId) {
1897
1904
  const record = resolveTimeZoneRecord(rawTimeZoneId);
1898
1905
  return queryTimeZoneRecord(record.id, record);
1899
1906
  }
1900
- const queryTimeZoneRecord = /* @__PURE__ */ memoize((normTimeZoneId, record) => "named" === record.kind ? new IntlTimeZone(normTimeZoneId, record.o, record.format) : new FixedTimeZone(normTimeZoneId, record.o, "fixed" === record.kind ? record._ : 0));
1907
+ const queryTimeZoneRecord = /*@__PURE__*/ memoize((normTimeZoneId, record) => "named" === record.kind ? new IntlTimeZone(normTimeZoneId, record.o, record.format) : new FixedTimeZone(normTimeZoneId, record.o, "fixed" === record.kind ? record._ : 0));
1901
1908
  var FixedTimeZone = class {
1902
1909
  constructor(id, compareKey, offsetNano) {
1903
1910
  this.id = id, this.o = compareKey, this._ = offsetNano;
@@ -1979,7 +1986,8 @@ var IntlTimeZone = class {
1979
1986
  return void 0 !== intlParts.era && "bce" === normalizeEraName(intlParts.era) ? 1 - year : year;
1980
1987
  })(intlParts), parseInt(intlParts.month), parseInt(intlParts.day)) + 3600 * parseInt(intlParts.hour) + 60 * parseInt(intlParts.minute) + parseInt(intlParts.second) - epochSec;
1981
1988
  })(format), ((timeZoneId) => {
1982
- return timeZonePeriodDaysByName[timeZoneId.split("/").pop()] || 60;
1989
+ const timeZoneName = timeZoneId.split("/").pop();
1990
+ return timeZonePeriodDaysByName[timeZoneName] || 60;
1983
1991
  })(id));
1984
1992
  }
1985
1993
  C(epochNano) {
@@ -2203,12 +2211,12 @@ function offsetRegExpStr(separatorIndex) {
2203
2211
  return "([+-])" + timeRegExpStr(separatorIndex);
2204
2212
  }
2205
2213
  const dateTimeRegExpStr = "(?:(?:([+-])(\\d{6}))|(\\d{4}))(-?)(\\d{2})\\4(\\d{2})(?:[T ]" + timeRegExpStr(8) + "(Z|" + offsetRegExpStr(15) + ")?)?";
2206
- const yearMonthRegExp = /* @__PURE__ */ createRegExp("(?:(?:([+-])(\\d{6}))|(\\d{4}))-?(\\d{2})((?:\\[(!?)([^\\]]*)\\]){0,9})");
2207
- const monthDayRegExp = /* @__PURE__ */ createRegExp("(?:--)?(\\d{2})-?(\\d{2})((?:\\[(!?)([^\\]]*)\\]){0,9})");
2208
- const dateTimeRegExp = /* @__PURE__ */ createRegExp(dateTimeRegExpStr + "((?:\\[(!?)([^\\]]*)\\]){0,9})");
2209
- const timeRegExp = /* @__PURE__ */ createRegExp("T?" + timeRegExpStr(2) + `(${offsetRegExpStr(9)})?((?:\\[(!?)([^\\]]*)\\]){0,9})`);
2210
- const annotationRegExp = /* @__PURE__ */ new RegExp("\\[(!?)([^\\]]*)\\]", "g");
2211
- const durationRegExp = /* @__PURE__ */ createRegExp("([+-])?P(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(?:T(?:(\\d+)(?:[.,](\\d{1,9}))?H)?(?:(\\d+)(?:[.,](\\d{1,9}))?M)?(?:(\\d+)(?:[.,](\\d{1,9}))?S)?)?");
2214
+ const yearMonthRegExp = /*@__PURE__*/ createRegExp("(?:(?:([+-])(\\d{6}))|(\\d{4}))-?(\\d{2})((?:\\[(!?)([^\\]]*)\\]){0,9})");
2215
+ const monthDayRegExp = /*@__PURE__*/ createRegExp("(?:--)?(\\d{2})-?(\\d{2})((?:\\[(!?)([^\\]]*)\\]){0,9})");
2216
+ const dateTimeRegExp = /*@__PURE__*/ createRegExp(dateTimeRegExpStr + "((?:\\[(!?)([^\\]]*)\\]){0,9})");
2217
+ const timeRegExp = /*@__PURE__*/ createRegExp("T?" + timeRegExpStr(2) + `(${offsetRegExpStr(9)})?((?:\\[(!?)([^\\]]*)\\]){0,9})`);
2218
+ const annotationRegExp = /*@__PURE__*/ new RegExp("\\[(!?)([^\\]]*)\\]", "g");
2219
+ const durationRegExp = /*@__PURE__*/ createRegExp("([+-])?P(\\d+Y)?(\\d+M)?(\\d+W)?(\\d+D)?(?:T(?:(\\d+)(?:[.,](\\d{1,9}))?H)?(?:(\\d+)(?:[.,](\\d{1,9}))?M)?(?:(\\d+)(?:[.,](\\d{1,9}))?S)?)?");
2212
2220
  function parseDateTimeLike(s) {
2213
2221
  const parts = dateTimeRegExp.exec(s);
2214
2222
  return parts ? ((parts) => {
@@ -2486,8 +2494,8 @@ const timeDefaultShapeFields = {
2486
2494
  minute: "numeric",
2487
2495
  second: "numeric"
2488
2496
  };
2489
- const dateTimeDefaultShapeFields = /* @__PURE__ */ Object.assign({}, dateDefaultShapeFields, timeDefaultShapeFields);
2490
- const zonedDateTimeDefaultShapeFields = /* @__PURE__ */ Object.assign({}, dateTimeDefaultShapeFields, { timeZoneName: "short" });
2497
+ const dateTimeDefaultShapeFields = /*@__PURE__*/ Object.assign({}, dateDefaultShapeFields, timeDefaultShapeFields);
2498
+ const zonedDateTimeDefaultShapeFields = /*@__PURE__*/ Object.assign({}, dateTimeDefaultShapeFields, { timeZoneName: "short" });
2491
2499
  const yearMonthDefaultShapeFields = {
2492
2500
  year: "numeric",
2493
2501
  month: "numeric"
@@ -2511,15 +2519,15 @@ const timeShapeFieldNames = [
2511
2519
  "fractionalSecondDigits",
2512
2520
  "timeStyle"
2513
2521
  ];
2514
- const dateTimeShapeFieldNames = /* @__PURE__ */ dateShapeFieldNames.concat(timeShapeFieldNames);
2515
- const yearMonthIgnoredFieldNames = /* @__PURE__ */ ["weekday", "day"].concat(timeShapeFieldNames);
2516
- const monthDayIgnoredFieldNames = /* @__PURE__ */ ["weekday", "year"].concat(timeShapeFieldNames);
2517
- const transformInstantOptions = /* @__PURE__ */ createOptionsTransformer(dateTimeShapeFieldNames, [], [], dateTimeDefaultShapeFields);
2518
- const transformZonedOptions = /* @__PURE__ */ createOptionsTransformer(dateTimeShapeFieldNames, [], [], zonedDateTimeDefaultShapeFields);
2519
- const transformDateTimeOptions = /* @__PURE__ */ createOptionsTransformer(dateTimeShapeFieldNames, [], ["timeZoneName"], dateTimeDefaultShapeFields);
2520
- const transformDateOptions = /* @__PURE__ */ createOptionsTransformer(dateShapeFieldNames, timeShapeFieldNames, ["timeZoneName"], dateDefaultShapeFields);
2521
- const transformTimeOptions = /* @__PURE__ */ createOptionsTransformer(timeShapeFieldNames, dateShapeFieldNames, ["timeZoneName", "era"], timeDefaultShapeFields);
2522
- const transformYearMonthOptions = /* @__PURE__ */ createOptionsTransformer([
2522
+ const dateTimeShapeFieldNames = /*@__PURE__*/ dateShapeFieldNames.concat(timeShapeFieldNames);
2523
+ const yearMonthIgnoredFieldNames = /*@__PURE__*/ ["weekday", "day"].concat(timeShapeFieldNames);
2524
+ const monthDayIgnoredFieldNames = /*@__PURE__*/ ["weekday", "year"].concat(timeShapeFieldNames);
2525
+ const transformInstantOptions = /*@__PURE__*/ createOptionsTransformer(dateTimeShapeFieldNames, [], [], dateTimeDefaultShapeFields);
2526
+ const transformZonedOptions = /*@__PURE__*/ createOptionsTransformer(dateTimeShapeFieldNames, [], [], zonedDateTimeDefaultShapeFields);
2527
+ const transformDateTimeOptions = /*@__PURE__*/ createOptionsTransformer(dateTimeShapeFieldNames, [], ["timeZoneName"], dateTimeDefaultShapeFields);
2528
+ const transformDateOptions = /*@__PURE__*/ createOptionsTransformer(dateShapeFieldNames, timeShapeFieldNames, ["timeZoneName"], dateDefaultShapeFields);
2529
+ const transformTimeOptions = /*@__PURE__*/ createOptionsTransformer(timeShapeFieldNames, dateShapeFieldNames, ["timeZoneName", "era"], timeDefaultShapeFields);
2530
+ const transformYearMonthOptions = /*@__PURE__*/ createOptionsTransformer([
2523
2531
  "year",
2524
2532
  "month",
2525
2533
  "dateStyle"
@@ -2541,7 +2549,7 @@ const transformYearMonthOptions = /* @__PURE__ */ createOptionsTransformer([
2541
2549
  month: "numeric"
2542
2550
  }
2543
2551
  });
2544
- const transformMonthDayOptions = /* @__PURE__ */ createOptionsTransformer([
2552
+ const transformMonthDayOptions = /*@__PURE__*/ createOptionsTransformer([
2545
2553
  "month",
2546
2554
  "day",
2547
2555
  "dateStyle"
@@ -2715,8 +2723,8 @@ function resolveBasicCalendarId(rawCalendarId) {
2715
2723
  function resolveBasicCalendarArg(rawCalendarId = isoCalendarId) {
2716
2724
  return resolveBasicCalendarId(rawCalendarId);
2717
2725
  }
2718
- const zonedDateTimeSlotsMap = /* @__PURE__ */ new WeakMap();
2719
- const ZonedDateTime = /* @__PURE__ */ defineTemporalClass(ZonedDateTimeBranding, class {
2726
+ const zonedDateTimeSlotsMap = /*@__PURE__*/ new WeakMap();
2727
+ const ZonedDateTime = /*@__PURE__*/ defineTemporalClass(ZonedDateTimeBranding, class {
2720
2728
  constructor(epochNanoseconds, timeZoneId, calendar = void 0) {
2721
2729
  const epochNano = checkEpochNanoInBounds(toBigInt(epochNanoseconds));
2722
2730
  const timeZone = queryTimeZone(refineTimeZoneId(timeZoneId));
@@ -2864,8 +2872,8 @@ function refineTimeZoneArg(arg) {
2864
2872
  }
2865
2873
  return ((arg) => resolveTimeZoneId(parseTimeZoneId(requireString(arg))))(arg);
2866
2874
  }
2867
- const instantSlotsMap = /* @__PURE__ */ new WeakMap();
2868
- const Instant = /* @__PURE__ */ defineTemporalClass(InstantBranding, class {
2875
+ const instantSlotsMap = /*@__PURE__*/ new WeakMap();
2876
+ const Instant = /*@__PURE__*/ defineTemporalClass(InstantBranding, class {
2869
2877
  constructor(epochNanoseconds) {
2870
2878
  const epochNano = checkEpochNanoInBounds(toBigInt(epochNanoseconds));
2871
2879
  initInstant(this, createEpochNanoSlots(epochNano));
@@ -2950,8 +2958,8 @@ const { toTemporalInstant: toTemporalInstant$1 } = { toTemporalInstant() {
2950
2958
  function initInstant(instance, slots) {
2951
2959
  return instantSlotsMap.set(instance, slots), attachDebugString(instance), instance;
2952
2960
  }
2953
- const plainMonthDaySlotsMap = /* @__PURE__ */ new WeakMap();
2954
- const PlainMonthDay = /* @__PURE__ */ defineTemporalClass(PlainMonthDayBranding, class {
2961
+ const plainMonthDaySlotsMap = /*@__PURE__*/ new WeakMap();
2962
+ const PlainMonthDay = /*@__PURE__*/ defineTemporalClass(PlainMonthDayBranding, class {
2955
2963
  constructor(isoMonth, isoDay, calendar = void 0, referenceIsoYear) {
2956
2964
  const isoMonthInt = toIntegerWithTrunc(isoMonth);
2957
2965
  const isoDayInt = toIntegerWithTrunc(isoDay);
@@ -3015,8 +3023,8 @@ function toPlainMonthDaySlots(arg, options) {
3015
3023
  function initPlainMonthDay(instance, slots) {
3016
3024
  return plainMonthDaySlotsMap.set(instance, slots), attachDebugString(instance), instance;
3017
3025
  }
3018
- const plainYearMonthSlotsMap = /* @__PURE__ */ new WeakMap();
3019
- const PlainYearMonth = /* @__PURE__ */ defineTemporalClass(PlainYearMonthBranding, class {
3026
+ const plainYearMonthSlotsMap = /*@__PURE__*/ new WeakMap();
3027
+ const PlainYearMonth = /*@__PURE__*/ defineTemporalClass(PlainYearMonthBranding, class {
3020
3028
  constructor(isoYear, isoMonth, calendar = void 0, referenceIsoDay) {
3021
3029
  const isoYearInt = toIntegerWithTrunc(isoYear);
3022
3030
  const isoMonthInt = toIntegerWithTrunc(isoMonth);
@@ -3108,8 +3116,8 @@ function getTemporalBrandingAndSlots(obj) {
3108
3116
  function validateBag(bag) {
3109
3117
  return (getTemporalBrandingAndSlots(bag) || void 0 !== bag.calendar || void 0 !== bag.timeZone) && throwTypeError("Invalid bag"), bag;
3110
3118
  }
3111
- const plainTimeSlotsMap = /* @__PURE__ */ new WeakMap();
3112
- const PlainTime = /* @__PURE__ */ defineTemporalClass(PlainTimeBranding, class {
3119
+ const plainTimeSlotsMap = /*@__PURE__*/ new WeakMap();
3120
+ const PlainTime = /*@__PURE__*/ defineTemporalClass(PlainTimeBranding, class {
3113
3121
  constructor(hour = 0, minute = 0, second = 0, millisecond = 0, microsecond = 0, nanosecond = 0) {
3114
3122
  const fields = validateTimeFields(mapProps(toIntegerWithTrunc, {
3115
3123
  hour,
@@ -3191,8 +3199,8 @@ function optionalToPlainTimeFields(timeArg) {
3191
3199
  function initPlainTime(instance, slots) {
3192
3200
  return plainTimeSlotsMap.set(instance, slots), attachDebugString(instance), instance;
3193
3201
  }
3194
- const plainDateTimeSlotsMap = /* @__PURE__ */ new WeakMap();
3195
- const PlainDateTime = /* @__PURE__ */ defineTemporalClass(PlainDateTimeBranding, class {
3202
+ const plainDateTimeSlotsMap = /*@__PURE__*/ new WeakMap();
3203
+ const PlainDateTime = /*@__PURE__*/ defineTemporalClass(PlainDateTimeBranding, class {
3196
3204
  constructor(isoYear, isoMonth, isoDay, hour = 0, minute = 0, second = 0, millisecond = 0, microsecond = 0, nanosecond = 0, calendar = void 0) {
3197
3205
  const fields = checkIsoDateTimeInBounds(validateIsoDateTimeFields(mapProps(toIntegerWithTrunc, {
3198
3206
  year: isoYear,
@@ -3303,8 +3311,8 @@ function toPlainDateTimeSlots(arg, options) {
3303
3311
  function initPlainDateTime(instance, slots) {
3304
3312
  return plainDateTimeSlotsMap.set(instance, slots), attachDebugString(instance), instance;
3305
3313
  }
3306
- const plainDateSlotsMap = /* @__PURE__ */ new WeakMap();
3307
- const PlainDate = /* @__PURE__ */ defineTemporalClass(PlainDateBranding, class {
3314
+ const plainDateSlotsMap = /*@__PURE__*/ new WeakMap();
3315
+ const PlainDate = /*@__PURE__*/ defineTemporalClass(PlainDateBranding, class {
3308
3316
  constructor(isoYear, isoMonth, isoDay, calendar = void 0) {
3309
3317
  const fields = checkIsoDateInBounds(validateIsoDateFields(mapProps(toIntegerWithTrunc, {
3310
3318
  year: isoYear,
@@ -3422,8 +3430,8 @@ function refineCalendarArg(arg) {
3422
3430
  }
3423
3431
  return ((arg) => resolveBasicCalendarId(parseCalendarId(requireString(arg))))(arg);
3424
3432
  }
3425
- const durationSlotsMap = /* @__PURE__ */ new WeakMap();
3426
- const Duration = /* @__PURE__ */ defineTemporalClass(DurationBranding, class {
3433
+ const durationSlotsMap = /*@__PURE__*/ new WeakMap();
3434
+ const Duration = /*@__PURE__*/ defineTemporalClass(DurationBranding, class {
3427
3435
  constructor(years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0, microseconds = 0, nanoseconds = 0) {
3428
3436
  const fields = validateDurationFields(mapProps(toStrictInteger, {
3429
3437
  years,
@@ -3516,7 +3524,7 @@ function refinePublicRelativeTo(relativeTo) {
3516
3524
  function initDuration(instance, slots) {
3517
3525
  return durationSlotsMap.set(instance, slots), attachDebugString(instance), instance;
3518
3526
  }
3519
- const Now = /* @__PURE__ */ Object.defineProperties({}, {
3527
+ const Now = /*@__PURE__*/ Object.defineProperties({}, {
3520
3528
  ...createStringTagDescriptors("Temporal.Now"),
3521
3529
  ...createPropDescriptors({
3522
3530
  timeZoneId() {
@@ -3540,7 +3548,7 @@ const Now = /* @__PURE__ */ Object.defineProperties({}, {
3540
3548
  }
3541
3549
  })
3542
3550
  });
3543
- const Temporal$2 = /* @__PURE__ */ Object.defineProperties({}, {
3551
+ const Temporal$3 = /*@__PURE__*/ Object.defineProperties({}, {
3544
3552
  ...createStringTagDescriptors("Temporal"),
3545
3553
  ...createPropDescriptors({
3546
3554
  PlainYearMonth,
@@ -3556,13 +3564,13 @@ const Temporal$2 = /* @__PURE__ */ Object.defineProperties({}, {
3556
3564
  });
3557
3565
  //#endregion
3558
3566
  //#region ../../node_modules/.pnpm/temporal-polyfill@1.0.1/node_modules/temporal-polyfill/index.js
3559
- const Temporal$1 = NativeTemporal || Temporal$2;
3567
+ const Temporal$2 = NativeTemporal || Temporal$3;
3560
3568
  NativeTemporal && Date.prototype.toTemporalInstant;
3561
3569
  //#endregion
3562
3570
  //#region src/mq.ts
3563
- const Temporal = Temporal$1;
3571
+ const Temporal$1 = Temporal$2;
3564
3572
  const defaultEventName = "fedify:queue";
3565
- const defaultOrderingRetryDelay = Temporal.Duration.from({ seconds: 5 });
3573
+ const defaultOrderingRetryDelay = Temporal$1.Duration.from({ seconds: 5 });
3566
3574
  /**
3567
3575
  * An error raised when an event send is not acknowledged.
3568
3576
  *
@@ -3591,7 +3599,7 @@ var NetlifyMessageQueueSendError = class extends Error {
3591
3599
  };
3592
3600
  const orderingOptions = /* @__PURE__ */ new WeakMap();
3593
3601
  function duration(value, defaultValue, name) {
3594
- const result = value == null ? defaultValue : Temporal.Duration.from(value);
3602
+ const result = value == null ? defaultValue : Temporal$1.Duration.from(value);
3595
3603
  const milliseconds = result.total("milliseconds");
3596
3604
  if (!Number.isFinite(milliseconds) || milliseconds <= 0) throw new RangeError(`${name} must be a positive finite duration.`);
3597
3605
  return result;
@@ -3782,7 +3790,7 @@ var NetlifyMessageQueue = class {
3782
3790
  };
3783
3791
  //#endregion
3784
3792
  //#region src/handler.ts
3785
- const messageTypes = new Set([
3793
+ const messageTypes = /* @__PURE__ */ new Set([
3786
3794
  "fanout",
3787
3795
  "inbox",
3788
3796
  "outbox",
@@ -3878,6 +3886,117 @@ function createNetlifyQueueHandler(options) {
3878
3886
  return createNetlifyQueueHandlerWith(_netlify_async_workloads.asyncWorkloadFn, options);
3879
3887
  }
3880
3888
  //#endregion
3889
+ //#region src/kv.ts
3890
+ const Temporal = Temporal$2;
3891
+ const MAX_BLOB_KEY_BYTES = 600;
3892
+ const BLOB_KEY_PREFIX = "fedify1.";
3893
+ const BLOB_KEY_SEPARATOR = ".";
3894
+ const textDecoder = new TextDecoder();
3895
+ /**
3896
+ * A key-value store that uses Netlify Blobs.
3897
+ *
3898
+ * @since 2.4.0
3899
+ */
3900
+ var NetlifyBlobsKvStore = class {
3901
+ #store;
3902
+ /**
3903
+ * Creates a new Netlify Blobs-backed key-value store.
3904
+ * @param store The Netlify Blobs store to use.
3905
+ */
3906
+ constructor(store) {
3907
+ this.#store = store;
3908
+ }
3909
+ serializeKey(key) {
3910
+ const serialized = BLOB_KEY_PREFIX + key.map((part) => (0, byte_encodings_base64url.encodeBase64Url)(part)).join(BLOB_KEY_SEPARATOR) + BLOB_KEY_SEPARATOR;
3911
+ if (new TextEncoder().encode(serialized).byteLength > MAX_BLOB_KEY_BYTES) throw new RangeError("The encoded key exceeds Netlify Blobs' 600-byte key limit.");
3912
+ return serialized;
3913
+ }
3914
+ deserializeKey(key) {
3915
+ return key.slice(8, -1).split(BLOB_KEY_SEPARATOR).map((part) => textDecoder.decode((0, byte_encodings_base64url.decodeBase64Url)(part)));
3916
+ }
3917
+ serializePrefix(prefix) {
3918
+ return prefix == null ? BLOB_KEY_PREFIX : this.serializeKey(prefix);
3919
+ }
3920
+ isAbsent(metadata) {
3921
+ if (metadata.tombstone === true) return true;
3922
+ const expireIn = metadata.expireIn;
3923
+ return typeof expireIn === "number" && expireIn <= Temporal.Now.instant().epochMilliseconds;
3924
+ }
3925
+ getEtag(entry) {
3926
+ if (entry?.etag == null) throw new Error("Netlify Blobs did not return an ETag.");
3927
+ return entry.etag;
3928
+ }
3929
+ /**
3930
+ * {@inheritDoc KvStore.get}
3931
+ */
3932
+ async get(key) {
3933
+ const result = await this.#store.getWithMetadata(this.serializeKey(key), { type: "json" });
3934
+ if (result === null || this.isAbsent(result.metadata)) return void 0;
3935
+ return result.data;
3936
+ }
3937
+ /**
3938
+ * {@inheritDoc KvStore.set}
3939
+ */
3940
+ async set(key, value, options) {
3941
+ const expireIn = options?.ttl == null ? null : Temporal.Now.instant().epochMilliseconds + options.ttl.total("millisecond");
3942
+ await this.#store.setJSON(this.serializeKey(key), value, { metadata: { "expireIn": expireIn } });
3943
+ }
3944
+ /**
3945
+ * {@inheritDoc KvStore.delete}
3946
+ */
3947
+ delete(key) {
3948
+ return this.#store.delete(this.serializeKey(key));
3949
+ }
3950
+ /**
3951
+ * {@inheritDoc KvStore.list}
3952
+ */
3953
+ async *list(prefix) {
3954
+ const pages = this.#store.list({
3955
+ paginate: true,
3956
+ prefix: this.serializePrefix(prefix)
3957
+ });
3958
+ for await (const page of pages) for (const blob of page.blobs) {
3959
+ const key = this.deserializeKey(blob.key);
3960
+ const value = await this.get(key);
3961
+ if (value === void 0) continue;
3962
+ yield {
3963
+ key,
3964
+ value
3965
+ };
3966
+ }
3967
+ }
3968
+ /**
3969
+ * {@inheritDoc KvStore.cas}
3970
+ */
3971
+ async cas(key, expectedValue, newValue, options) {
3972
+ while (true) {
3973
+ const entry = await this.#store.getWithMetadata(this.serializeKey(key), {
3974
+ consistency: "strong",
3975
+ type: "json"
3976
+ });
3977
+ if (!(0, es_toolkit.isEqual)(entry === null || this.isAbsent(entry.metadata) ? void 0 : entry.data, expectedValue)) return false;
3978
+ if (entry === null && newValue === void 0) return true;
3979
+ const serializedKey = this.serializeKey(key);
3980
+ if (newValue === void 0) {
3981
+ if ((await this.#store.setJSON(serializedKey, null, {
3982
+ onlyIfMatch: this.getEtag(entry),
3983
+ metadata: { tombstone: true }
3984
+ })).modified) return true;
3985
+ continue;
3986
+ }
3987
+ const metadata = { "expireIn": options?.ttl == null ? null : Temporal.Now.instant().epochMilliseconds + options.ttl.total("millisecond") };
3988
+ if ((entry === null ? await this.#store.setJSON(serializedKey, newValue, {
3989
+ onlyIfNew: true,
3990
+ metadata
3991
+ }) : await this.#store.setJSON(serializedKey, newValue, {
3992
+ onlyIfMatch: this.getEtag(entry),
3993
+ metadata
3994
+ })).modified) return true;
3995
+ }
3996
+ }
3997
+ };
3998
+ //#endregion
3999
+ exports.NetlifyBlobsKvStore = NetlifyBlobsKvStore;
3881
4000
  exports.NetlifyMessageQueue = NetlifyMessageQueue;
3882
4001
  exports.NetlifyMessageQueueSendError = NetlifyMessageQueueSendError;
3883
4002
  exports.createNetlifyQueueHandler = createNetlifyQueueHandler;
package/dist/mod.d.cts CHANGED
@@ -1,9 +1,49 @@
1
1
  /// <reference lib="esnext.temporal" />
2
- import { Federation, KvStore, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify/federation";
2
+ import { Federation, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify/federation";
3
3
  import { AsyncWorkloadEvent, CustomAsyncWorkloadEvent, asyncWorkloadFn } from "@netlify/async-workloads";
4
4
 
5
5
  //#region src/types.d.ts
6
6
  /**
7
+ * The subset of Netlify's Blobs `Store` used by this package.
8
+ *
9
+ * The real Netlify Blobs `Store` satisfies this interface. The narrower
10
+ * interface also keeps Netlify Blobs optional and makes it possible to supply
11
+ * a test double.
12
+ *
13
+ * @since 2.4.0
14
+ */
15
+ interface NetlifyBlobsStore {
16
+ getWithMetadata(key: string, options: {
17
+ readonly consistency?: "eventual" | "strong";
18
+ readonly type: "json";
19
+ }): Promise<{
20
+ readonly data: unknown;
21
+ readonly etag?: string;
22
+ readonly metadata: Record<string, unknown>;
23
+ } | null>;
24
+ setJSON(key: string, data: unknown, options?: {
25
+ readonly metadata?: Record<string, unknown>;
26
+ } & ({
27
+ readonly onlyIfNew?: boolean;
28
+ readonly onlyIfMatch?: never;
29
+ } | {
30
+ readonly onlyIfMatch?: string;
31
+ readonly onlyIfNew?: never;
32
+ })): Promise<{
33
+ readonly etag?: string;
34
+ readonly modified: boolean;
35
+ }>;
36
+ delete(key: string): Promise<void>;
37
+ list(options: {
38
+ readonly paginate: true;
39
+ readonly prefix?: string;
40
+ }): AsyncIterable<{
41
+ readonly blobs: readonly {
42
+ readonly key: string;
43
+ }[];
44
+ }>;
45
+ }
46
+ /**
7
47
  * The subset of Netlify's `AsyncWorkloadsClient` used by this package.
8
48
  *
9
49
  * The real `AsyncWorkloadsClient` satisfies this interface. The narrower
@@ -176,4 +216,44 @@ type WorkloadFunction = ReturnType<typeof asyncWorkloadFn<NetlifyQueueEvent>>;
176
216
  */
177
217
  declare function createNetlifyQueueHandler<TContextData>(options: NetlifyQueueHandlerOptions<TContextData>): WorkloadFunction;
178
218
  //#endregion
179
- export { type NetlifyAsyncWorkloadsClient, NetlifyMessageQueue, type NetlifyMessageQueueOptions, NetlifyMessageQueueSendError, type NetlifyQueueEvent, type NetlifyQueueEventData, type NetlifyQueueHandlerOptions, createNetlifyQueueHandler };
219
+ //#region src/kv.d.ts
220
+ /**
221
+ * A key-value store that uses Netlify Blobs.
222
+ *
223
+ * @since 2.4.0
224
+ */
225
+ declare class NetlifyBlobsKvStore implements KvStore {
226
+ #private;
227
+ /**
228
+ * Creates a new Netlify Blobs-backed key-value store.
229
+ * @param store The Netlify Blobs store to use.
230
+ */
231
+ constructor(store: NetlifyBlobsStore);
232
+ private serializeKey;
233
+ private deserializeKey;
234
+ private serializePrefix;
235
+ private isAbsent;
236
+ private getEtag;
237
+ /**
238
+ * {@inheritDoc KvStore.get}
239
+ */
240
+ get<T = unknown>(key: KvKey): Promise<T | undefined>;
241
+ /**
242
+ * {@inheritDoc KvStore.set}
243
+ */
244
+ set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
245
+ /**
246
+ * {@inheritDoc KvStore.delete}
247
+ */
248
+ delete(key: KvKey): Promise<void>;
249
+ /**
250
+ * {@inheritDoc KvStore.list}
251
+ */
252
+ list(prefix?: KvKey): AsyncIterable<KvStoreListEntry>;
253
+ /**
254
+ * {@inheritDoc KvStore.cas}
255
+ */
256
+ cas(key: KvKey, expectedValue: unknown, newValue: unknown, options?: KvStoreSetOptions): Promise<boolean>;
257
+ }
258
+ //#endregion
259
+ export { type NetlifyAsyncWorkloadsClient, NetlifyBlobsKvStore, type NetlifyBlobsStore, NetlifyMessageQueue, type NetlifyMessageQueueOptions, NetlifyMessageQueueSendError, type NetlifyQueueEvent, type NetlifyQueueEventData, type NetlifyQueueHandlerOptions, createNetlifyQueueHandler };
package/dist/mod.d.ts CHANGED
@@ -1,9 +1,49 @@
1
1
  /// <reference lib="esnext.temporal" />
2
2
  import { AsyncWorkloadEvent, CustomAsyncWorkloadEvent, asyncWorkloadFn } from "@netlify/async-workloads";
3
- import { Federation, KvStore, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify/federation";
3
+ import { Federation, KvKey, KvStore, KvStoreListEntry, KvStoreSetOptions, Message, MessageQueue, MessageQueueEnqueueOptions, MessageQueueListenOptions } from "@fedify/fedify/federation";
4
4
 
5
5
  //#region src/types.d.ts
6
6
  /**
7
+ * The subset of Netlify's Blobs `Store` used by this package.
8
+ *
9
+ * The real Netlify Blobs `Store` satisfies this interface. The narrower
10
+ * interface also keeps Netlify Blobs optional and makes it possible to supply
11
+ * a test double.
12
+ *
13
+ * @since 2.4.0
14
+ */
15
+ interface NetlifyBlobsStore {
16
+ getWithMetadata(key: string, options: {
17
+ readonly consistency?: "eventual" | "strong";
18
+ readonly type: "json";
19
+ }): Promise<{
20
+ readonly data: unknown;
21
+ readonly etag?: string;
22
+ readonly metadata: Record<string, unknown>;
23
+ } | null>;
24
+ setJSON(key: string, data: unknown, options?: {
25
+ readonly metadata?: Record<string, unknown>;
26
+ } & ({
27
+ readonly onlyIfNew?: boolean;
28
+ readonly onlyIfMatch?: never;
29
+ } | {
30
+ readonly onlyIfMatch?: string;
31
+ readonly onlyIfNew?: never;
32
+ })): Promise<{
33
+ readonly etag?: string;
34
+ readonly modified: boolean;
35
+ }>;
36
+ delete(key: string): Promise<void>;
37
+ list(options: {
38
+ readonly paginate: true;
39
+ readonly prefix?: string;
40
+ }): AsyncIterable<{
41
+ readonly blobs: readonly {
42
+ readonly key: string;
43
+ }[];
44
+ }>;
45
+ }
46
+ /**
7
47
  * The subset of Netlify's `AsyncWorkloadsClient` used by this package.
8
48
  *
9
49
  * The real `AsyncWorkloadsClient` satisfies this interface. The narrower
@@ -176,4 +216,44 @@ type WorkloadFunction = ReturnType<typeof asyncWorkloadFn<NetlifyQueueEvent>>;
176
216
  */
177
217
  declare function createNetlifyQueueHandler<TContextData>(options: NetlifyQueueHandlerOptions<TContextData>): WorkloadFunction;
178
218
  //#endregion
179
- export { type NetlifyAsyncWorkloadsClient, NetlifyMessageQueue, type NetlifyMessageQueueOptions, NetlifyMessageQueueSendError, type NetlifyQueueEvent, type NetlifyQueueEventData, type NetlifyQueueHandlerOptions, createNetlifyQueueHandler };
219
+ //#region src/kv.d.ts
220
+ /**
221
+ * A key-value store that uses Netlify Blobs.
222
+ *
223
+ * @since 2.4.0
224
+ */
225
+ declare class NetlifyBlobsKvStore implements KvStore {
226
+ #private;
227
+ /**
228
+ * Creates a new Netlify Blobs-backed key-value store.
229
+ * @param store The Netlify Blobs store to use.
230
+ */
231
+ constructor(store: NetlifyBlobsStore);
232
+ private serializeKey;
233
+ private deserializeKey;
234
+ private serializePrefix;
235
+ private isAbsent;
236
+ private getEtag;
237
+ /**
238
+ * {@inheritDoc KvStore.get}
239
+ */
240
+ get<T = unknown>(key: KvKey): Promise<T | undefined>;
241
+ /**
242
+ * {@inheritDoc KvStore.set}
243
+ */
244
+ set(key: KvKey, value: unknown, options?: KvStoreSetOptions | undefined): Promise<void>;
245
+ /**
246
+ * {@inheritDoc KvStore.delete}
247
+ */
248
+ delete(key: KvKey): Promise<void>;
249
+ /**
250
+ * {@inheritDoc KvStore.list}
251
+ */
252
+ list(prefix?: KvKey): AsyncIterable<KvStoreListEntry>;
253
+ /**
254
+ * {@inheritDoc KvStore.cas}
255
+ */
256
+ cas(key: KvKey, expectedValue: unknown, newValue: unknown, options?: KvStoreSetOptions): Promise<boolean>;
257
+ }
258
+ //#endregion
259
+ export { type NetlifyAsyncWorkloadsClient, NetlifyBlobsKvStore, type NetlifyBlobsStore, NetlifyMessageQueue, type NetlifyMessageQueueOptions, NetlifyMessageQueueSendError, type NetlifyQueueEvent, type NetlifyQueueEventData, type NetlifyQueueHandlerOptions, createNetlifyQueueHandler };
package/dist/mod.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Temporal } from "temporal-polyfill";
2
2
  import { ErrorDoNotRetry, asyncWorkloadFn } from "@netlify/async-workloads";
3
+ import { decodeBase64Url, encodeBase64Url } from "byte-encodings/base64url";
4
+ import { isEqual } from "es-toolkit";
3
5
  //#region src/mq.ts
4
6
  const defaultEventName = "fedify:queue";
5
7
  const defaultOrderingRetryDelay = Temporal.Duration.from({ seconds: 5 });
@@ -222,7 +224,7 @@ var NetlifyMessageQueue = class {
222
224
  };
223
225
  //#endregion
224
226
  //#region src/handler.ts
225
- const messageTypes = new Set([
227
+ const messageTypes = /* @__PURE__ */ new Set([
226
228
  "fanout",
227
229
  "inbox",
228
230
  "outbox",
@@ -318,4 +320,113 @@ function createNetlifyQueueHandler(options) {
318
320
  return createNetlifyQueueHandlerWith(asyncWorkloadFn, options);
319
321
  }
320
322
  //#endregion
321
- export { NetlifyMessageQueue, NetlifyMessageQueueSendError, createNetlifyQueueHandler };
323
+ //#region src/kv.ts
324
+ const MAX_BLOB_KEY_BYTES = 600;
325
+ const BLOB_KEY_PREFIX = "fedify1.";
326
+ const BLOB_KEY_SEPARATOR = ".";
327
+ const textDecoder = new TextDecoder();
328
+ /**
329
+ * A key-value store that uses Netlify Blobs.
330
+ *
331
+ * @since 2.4.0
332
+ */
333
+ var NetlifyBlobsKvStore = class {
334
+ #store;
335
+ /**
336
+ * Creates a new Netlify Blobs-backed key-value store.
337
+ * @param store The Netlify Blobs store to use.
338
+ */
339
+ constructor(store) {
340
+ this.#store = store;
341
+ }
342
+ serializeKey(key) {
343
+ const serialized = BLOB_KEY_PREFIX + key.map((part) => encodeBase64Url(part)).join(BLOB_KEY_SEPARATOR) + BLOB_KEY_SEPARATOR;
344
+ if (new TextEncoder().encode(serialized).byteLength > MAX_BLOB_KEY_BYTES) throw new RangeError("The encoded key exceeds Netlify Blobs' 600-byte key limit.");
345
+ return serialized;
346
+ }
347
+ deserializeKey(key) {
348
+ return key.slice(8, -1).split(BLOB_KEY_SEPARATOR).map((part) => textDecoder.decode(decodeBase64Url(part)));
349
+ }
350
+ serializePrefix(prefix) {
351
+ return prefix == null ? BLOB_KEY_PREFIX : this.serializeKey(prefix);
352
+ }
353
+ isAbsent(metadata) {
354
+ if (metadata.tombstone === true) return true;
355
+ const expireIn = metadata.expireIn;
356
+ return typeof expireIn === "number" && expireIn <= Temporal.Now.instant().epochMilliseconds;
357
+ }
358
+ getEtag(entry) {
359
+ if (entry?.etag == null) throw new Error("Netlify Blobs did not return an ETag.");
360
+ return entry.etag;
361
+ }
362
+ /**
363
+ * {@inheritDoc KvStore.get}
364
+ */
365
+ async get(key) {
366
+ const result = await this.#store.getWithMetadata(this.serializeKey(key), { type: "json" });
367
+ if (result === null || this.isAbsent(result.metadata)) return void 0;
368
+ return result.data;
369
+ }
370
+ /**
371
+ * {@inheritDoc KvStore.set}
372
+ */
373
+ async set(key, value, options) {
374
+ const expireIn = options?.ttl == null ? null : Temporal.Now.instant().epochMilliseconds + options.ttl.total("millisecond");
375
+ await this.#store.setJSON(this.serializeKey(key), value, { metadata: { "expireIn": expireIn } });
376
+ }
377
+ /**
378
+ * {@inheritDoc KvStore.delete}
379
+ */
380
+ delete(key) {
381
+ return this.#store.delete(this.serializeKey(key));
382
+ }
383
+ /**
384
+ * {@inheritDoc KvStore.list}
385
+ */
386
+ async *list(prefix) {
387
+ const pages = this.#store.list({
388
+ paginate: true,
389
+ prefix: this.serializePrefix(prefix)
390
+ });
391
+ for await (const page of pages) for (const blob of page.blobs) {
392
+ const key = this.deserializeKey(blob.key);
393
+ const value = await this.get(key);
394
+ if (value === void 0) continue;
395
+ yield {
396
+ key,
397
+ value
398
+ };
399
+ }
400
+ }
401
+ /**
402
+ * {@inheritDoc KvStore.cas}
403
+ */
404
+ async cas(key, expectedValue, newValue, options) {
405
+ while (true) {
406
+ const entry = await this.#store.getWithMetadata(this.serializeKey(key), {
407
+ consistency: "strong",
408
+ type: "json"
409
+ });
410
+ if (!isEqual(entry === null || this.isAbsent(entry.metadata) ? void 0 : entry.data, expectedValue)) return false;
411
+ if (entry === null && newValue === void 0) return true;
412
+ const serializedKey = this.serializeKey(key);
413
+ if (newValue === void 0) {
414
+ if ((await this.#store.setJSON(serializedKey, null, {
415
+ onlyIfMatch: this.getEtag(entry),
416
+ metadata: { tombstone: true }
417
+ })).modified) return true;
418
+ continue;
419
+ }
420
+ const metadata = { "expireIn": options?.ttl == null ? null : Temporal.Now.instant().epochMilliseconds + options.ttl.total("millisecond") };
421
+ if ((entry === null ? await this.#store.setJSON(serializedKey, newValue, {
422
+ onlyIfNew: true,
423
+ metadata
424
+ }) : await this.#store.setJSON(serializedKey, newValue, {
425
+ onlyIfMatch: this.getEtag(entry),
426
+ metadata
427
+ })).modified) return true;
428
+ }
429
+ }
430
+ };
431
+ //#endregion
432
+ export { NetlifyBlobsKvStore, NetlifyMessageQueue, NetlifyMessageQueueSendError, createNetlifyQueueHandler };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fedify/netlify",
3
- "version": "2.4.0-pr.934.40+3331d302",
3
+ "version": "2.4.0",
4
4
  "description": "Integrate Fedify with Netlify Async Workloads",
5
5
  "keywords": [
6
6
  "Fedify",
@@ -47,22 +47,22 @@
47
47
  "package.json"
48
48
  ],
49
49
  "dependencies": {
50
+ "byte-encodings": "^1.0.11",
51
+ "es-toolkit": "1.46.1",
50
52
  "temporal-polyfill": "^1.0.1"
51
53
  },
52
54
  "peerDependencies": {
53
55
  "@netlify/async-workloads": "^0.0.106",
54
- "@fedify/fedify": "^2.4.0-pr.934.40+3331d302"
56
+ "@fedify/fedify": "^2.4.0"
55
57
  },
56
58
  "devDependencies": {
57
59
  "@js-temporal/polyfill": "^0.5.1",
58
- "@netlify/database": "^1.1.0",
59
60
  "@standard-schema/spec": "^1.1.0",
60
- "@types/node": "^22.17.0",
61
- "netlify-cli": "^26.2.0",
62
- "postgres": "^3.4.7",
61
+ "@netlify/blobs": "11.0.3",
62
+ "@types/node": "^24.12.2",
63
+ "netlify-cli": "^27.4.2",
63
64
  "tsdown": "^0.22.0",
64
- "typescript": "^6.0.0",
65
- "@fedify/postgres": "^2.4.0-pr.934.40+3331d302"
65
+ "typescript": "^6.0.0"
66
66
  },
67
67
  "scripts": {
68
68
  "build:self": "tsdown",