@dabble/patches 0.5.0 → 0.5.2

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.
@@ -1,5 +1,5 @@
1
1
  import "../../chunk-IZ2YBCUP.js";
2
- import { clampTimestamp, createServerTimestamp, timestampDiff } from "../../utils/dates.js";
2
+ import { clampTimestamp, getISO, timestampDiff } from "../../utils/dates.js";
3
3
  import { applyChanges } from "../shared/applyChanges.js";
4
4
  import { createVersion } from "./createVersion.js";
5
5
  import { getSnapshotAtRevision } from "./getSnapshotAtRevision.js";
@@ -15,7 +15,7 @@ async function commitChanges(store, docId, changes, sessionTimeoutMillis) {
15
15
  const currentState = applyChanges(initialState, currentChanges);
16
16
  const currentRev = currentChanges.at(-1)?.rev ?? initialRev;
17
17
  const baseRev = changes[0].baseRev ?? currentRev;
18
- const serverNow = createServerTimestamp();
18
+ const serverNow = getISO();
19
19
  let rev = baseRev + 1;
20
20
  changes.forEach((c) => {
21
21
  if (c.baseRev == null) c.baseRev = baseRev;
@@ -1,5 +1,6 @@
1
1
  import "../../chunk-IZ2YBCUP.js";
2
2
  import { createVersionMetadata } from "../../data/version.js";
3
+ import { getISO } from "../../utils/dates.js";
3
4
  async function createVersion(store, docId, state, changes, metadata) {
4
5
  if (changes.length === 0) return;
5
6
  const baseRev = changes[0].baseRev;
@@ -9,8 +10,8 @@ async function createVersion(store, docId, state, changes, metadata) {
9
10
  const sessionMetadata = createVersionMetadata({
10
11
  origin: "main",
11
12
  // Convert client timestamps to UTC for version metadata (enables lexicographic sorting)
12
- startedAt: new Date(changes[0].createdAt).toISOString(),
13
- endedAt: new Date(changes[changes.length - 1].createdAt).toISOString(),
13
+ startedAt: getISO(changes[0].createdAt),
14
+ endedAt: getISO(changes[changes.length - 1].createdAt),
14
15
  rev: changes[changes.length - 1].rev,
15
16
  baseRev,
16
17
  ...metadata
@@ -1,7 +1,7 @@
1
1
  import "../../chunk-IZ2YBCUP.js";
2
2
  import { createSortableId } from "crypto-id";
3
3
  import { createVersionMetadata } from "../../data/version.js";
4
- import { timestampDiff } from "../../utils/dates.js";
4
+ import { getISO, timestampDiff } from "../../utils/dates.js";
5
5
  import { applyChanges } from "../shared/applyChanges.js";
6
6
  import { getStateAtRevision } from "./getStateAtRevision.js";
7
7
  async function handleOfflineSessionsAndBatches(store, sessionTimeoutMillis, docId, changes, baseRev, batchId) {
@@ -41,8 +41,8 @@ async function handleOfflineSessionsAndBatches(store, sessionTimeoutMillis, docI
41
41
  groupId,
42
42
  origin: "offline",
43
43
  // Convert client timestamps to UTC for version metadata (enables lexicographic sorting)
44
- startedAt: new Date(sessionChanges[0].createdAt).toISOString(),
45
- endedAt: new Date(sessionChanges[sessionChanges.length - 1].createdAt).toISOString(),
44
+ startedAt: getISO(sessionChanges[0].createdAt),
45
+ endedAt: getISO(sessionChanges[sessionChanges.length - 1].createdAt),
46
46
  rev: sessionChanges[sessionChanges.length - 1].rev,
47
47
  baseRev
48
48
  });
@@ -1,7 +1,7 @@
1
1
  import "../chunk-IZ2YBCUP.js";
2
2
  import { inc } from "alphacounter";
3
3
  import { createId } from "crypto-id";
4
- import { createClientTimestamp } from "../utils/dates.js";
4
+ import { getLocalISO } from "../utils/dates.js";
5
5
  function createChangeId(rev) {
6
6
  return inc.from(rev) + createId(4);
7
7
  }
@@ -10,7 +10,7 @@ function createChange(baseRev, rev, ops, metadata) {
10
10
  return {
11
11
  id: createId(8),
12
12
  ops: baseRev,
13
- createdAt: createClientTimestamp(),
13
+ createdAt: getLocalISO(),
14
14
  ...rev
15
15
  };
16
16
  } else {
@@ -19,7 +19,7 @@ function createChange(baseRev, rev, ops, metadata) {
19
19
  baseRev,
20
20
  rev,
21
21
  ops,
22
- createdAt: createClientTimestamp(),
22
+ createdAt: getLocalISO(),
23
23
  ...metadata
24
24
  };
25
25
  }
package/dist/index.d.ts CHANGED
@@ -18,6 +18,7 @@ export { transformPatch } from './json-patch/transformPatch.js';
18
18
  export { JSONPatch, PathLike, WriteOptions } from './json-patch/JSONPatch.js';
19
19
  export { ApplyJSONPatchOptions, JSONPatchOpHandlerMap as JSONPatchCustomTypes, JSONPatchOp } from './json-patch/types.js';
20
20
  export { Branch, BranchStatus, Change, ChangeInput, ChangeMutator, EditableBranchMetadata, EditableVersionMetadata, ListChangesOptions, ListVersionsOptions, PatchesSnapshot, PatchesState, PathProxy, SyncingState, VersionMetadata } from './types.js';
21
+ export { clampTimestamp, extractTimezoneOffset, getISO, getLocalISO, getLocalTimezoneOffset, timestampDiff } from './utils/dates.js';
21
22
  export { add } from './json-patch/ops/add.js';
22
23
  export { copy } from './json-patch/ops/copy.js';
23
24
  export { increment } from './json-patch/ops/increment.js';
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ export * from "./data/change.js";
5
5
  export * from "./data/version.js";
6
6
  export * from "./event-signal.js";
7
7
  export * from "./json-patch/index.js";
8
+ export * from "./utils/dates.js";
8
9
  export {
9
10
  Delta
10
11
  };
@@ -2,7 +2,7 @@ import "../chunk-IZ2YBCUP.js";
2
2
  import { createId } from "crypto-id";
3
3
  import { createChange } from "../data/change.js";
4
4
  import { createVersionMetadata } from "../data/version.js";
5
- import { createServerTimestamp } from "../utils/dates.js";
5
+ import { getISO } from "../utils/dates.js";
6
6
  class PatchesBranchManager {
7
7
  constructor(store, patchesServer) {
8
8
  this.store = store;
@@ -31,7 +31,7 @@ class PatchesBranchManager {
31
31
  }
32
32
  const stateAtRev = (await this.patchesServer.getStateAtRevision(docId, rev)).state;
33
33
  const branchDocId = createId();
34
- const now = createServerTimestamp();
34
+ const now = getISO();
35
35
  const initialVersionMetadata = createVersionMetadata({
36
36
  origin: "main",
37
37
  // Branch doc versions are 'main' until merged
@@ -5,48 +5,39 @@
5
5
  * Server-side timestamps use UTC with Z suffix.
6
6
  */
7
7
  /**
8
- * Creates an ISO string with local timezone offset for client dates.
9
- * Example: "2025-12-26T14:00:00.000+04:00"
8
+ * Converts a Date or ISO string to UTC format without milliseconds.
9
+ * Example: "2025-12-26T10:00:00Z"
10
10
  */
11
- declare function createClientTimestamp(): string;
11
+ declare function getISO(date?: Date | string): string;
12
12
  /**
13
- * Creates an ISO string with Z suffix for server dates.
14
- * Example: "2025-12-26T10:00:00.000Z"
15
- */
16
- declare function createServerTimestamp(): string;
17
- /**
18
- * Parses an ISO string to a Date for comparisons.
13
+ * Formats a Date with a specific timezone offset string.
14
+ * The date is adjusted to display the correct local time for that offset.
19
15
  */
20
- declare function parseTimestamp(iso: string): Date;
16
+ declare function getLocalISO(date?: Date | string, offset?: string): string;
21
17
  /**
22
18
  * Calculates milliseconds between two ISO timestamps.
23
19
  * Returns (a - b) in milliseconds.
24
20
  */
25
21
  declare function timestampDiff(a: string, b: string): number;
26
- /**
27
- * Extracts the timezone offset string from an ISO timestamp.
28
- * Returns "+04:00", "-05:00", or "Z".
29
- */
30
- declare function extractTimezoneOffset(iso: string): string;
31
22
  /**
32
23
  * Clamps a timestamp to not exceed a limit, preserving the original timezone offset.
33
24
  * Returns the original if it's <= limit, otherwise returns limit in original's timezone.
34
25
  *
35
26
  * Example:
36
- * timestamp: "2025-12-26T18:00:00.000+04:00" (future)
37
- * limit: "2025-12-26T10:00:00.000Z" (server time)
38
- * result: "2025-12-26T14:00:00.000+04:00" (clamped, same instant as limit)
27
+ * timestamp: "2025-12-26T18:00:00+04:00" (future)
28
+ * limit: "2025-12-26T10:00:00Z" (server time)
29
+ * result: "2025-12-26T14:00:00+04:00" (clamped, same instant as limit)
39
30
  */
40
31
  declare function clampTimestamp(timestamp: string, limit: string): string;
41
32
  /**
42
- * Formats a Date with a specific timezone offset string.
43
- * The date is adjusted to display the correct local time for that offset.
33
+ * Extracts the timezone offset string from an ISO timestamp.
34
+ * Returns "+04:00", "-05:00", or "Z".
44
35
  */
45
- declare function formatWithOffset(date: Date, offset: string): string;
36
+ declare function extractTimezoneOffset(iso: string): string;
46
37
  /**
47
38
  * Gets the local timezone offset string for the current environment.
48
39
  * Returns "+04:00", "-05:00", or "Z" for UTC.
49
40
  */
50
41
  declare function getLocalTimezoneOffset(): string;
51
42
 
52
- export { clampTimestamp, createClientTimestamp, createServerTimestamp, extractTimezoneOffset, formatWithOffset, getLocalTimezoneOffset, parseTimestamp, timestampDiff };
43
+ export { clampTimestamp, extractTimezoneOffset, getISO, getLocalISO, getLocalTimezoneOffset, timestampDiff };
@@ -1,21 +1,19 @@
1
1
  import "../chunk-IZ2YBCUP.js";
2
- function createClientTimestamp() {
3
- const now = /* @__PURE__ */ new Date();
4
- return formatWithOffset(now, getLocalTimezoneOffset());
2
+ function getISO(date = /* @__PURE__ */ new Date()) {
3
+ const d = typeof date === "string" ? new Date(date) : date;
4
+ return d.toISOString().replace(/\.\d{3}/, "");
5
5
  }
6
- function createServerTimestamp() {
7
- return (/* @__PURE__ */ new Date()).toISOString();
8
- }
9
- function parseTimestamp(iso) {
10
- return new Date(iso);
6
+ function getLocalISO(date = /* @__PURE__ */ new Date(), offset = getLocalTimezoneOffset()) {
7
+ const match = offset.match(/([+-])(\d{2}):(\d{2})/);
8
+ if (offset === "Z" || !match) return getISO(date);
9
+ const sign = match[1] === "+" ? 1 : -1;
10
+ const offsetMinutes = sign * (parseInt(match[2]) * 60 + parseInt(match[3]));
11
+ const localDate = new Date((typeof date === "string" ? new Date(date) : date).getTime() + offsetMinutes * 60 * 1e3);
12
+ return getISO(localDate).slice(0, -1) + offset;
11
13
  }
12
14
  function timestampDiff(a, b) {
13
15
  return new Date(a).getTime() - new Date(b).getTime();
14
16
  }
15
- function extractTimezoneOffset(iso) {
16
- const match = iso.match(/([+-]\d{2}:\d{2}|Z)$/);
17
- return match ? match[1] : "Z";
18
- }
19
17
  function clampTimestamp(timestamp, limit) {
20
18
  const timestampDate = new Date(timestamp);
21
19
  const limitDate = new Date(limit);
@@ -23,19 +21,11 @@ function clampTimestamp(timestamp, limit) {
23
21
  return timestamp;
24
22
  }
25
23
  const offset = extractTimezoneOffset(timestamp);
26
- return formatWithOffset(limitDate, offset);
24
+ return getLocalISO(limitDate, offset);
27
25
  }
28
- function formatWithOffset(date, offset) {
29
- if (offset === "Z") {
30
- return date.toISOString();
31
- }
32
- const match = offset.match(/([+-])(\d{2}):(\d{2})/);
33
- if (!match) return date.toISOString();
34
- const sign = match[1] === "+" ? 1 : -1;
35
- const offsetMinutes = sign * (parseInt(match[2]) * 60 + parseInt(match[3]));
36
- const localDate = new Date(date.getTime() + offsetMinutes * 60 * 1e3);
37
- const iso = localDate.toISOString();
38
- return iso.slice(0, -1) + offset;
26
+ function extractTimezoneOffset(iso) {
27
+ const match = iso.match(/([+-]\d{2}:\d{2}|Z)$/);
28
+ return match ? match[1] : "Z";
39
29
  }
40
30
  function getLocalTimezoneOffset() {
41
31
  const offset = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
@@ -47,11 +37,9 @@ function getLocalTimezoneOffset() {
47
37
  }
48
38
  export {
49
39
  clampTimestamp,
50
- createClientTimestamp,
51
- createServerTimestamp,
52
40
  extractTimezoneOffset,
53
- formatWithOffset,
41
+ getISO,
42
+ getLocalISO,
54
43
  getLocalTimezoneOffset,
55
- parseTimestamp,
56
44
  timestampDiff
57
45
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dabble/patches",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Immutable JSON Patch implementation based on RFC 6902 supporting operational transformation and last-writer-wins",
5
5
  "author": "Jacob Wright <jacwright@gmail.com>",
6
6
  "bugs": {