@temporal-cortex/truth-engine 0.1.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 +172 -0
- package/dist/index.d.ts +83 -0
- package/dist/index.js +88 -0
- package/package.json +40 -0
- package/wasm/truth_engine_wasm.cjs +383 -0
- package/wasm/truth_engine_wasm.d.ts +56 -0
- package/wasm/truth_engine_wasm_bg.wasm +0 -0
- package/wasm/truth_engine_wasm_bg.wasm.d.ts +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# @temporal-cortex/truth-engine
|
|
2
|
+
|
|
3
|
+
WASM-powered RRULE expansion, conflict detection, free/busy computation, and multi-calendar availability merging for Node.js.
|
|
4
|
+
|
|
5
|
+
This package wraps the Rust `truth-engine` library via WebAssembly, providing near-native performance for deterministic calendar operations in JavaScript/TypeScript environments.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @temporal-cortex/truth-engine
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @temporal-cortex/truth-engine
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### Expand Recurrence Rules
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { expandRRule } from "@temporal-cortex/truth-engine";
|
|
21
|
+
|
|
22
|
+
// "Every Tuesday at 2pm Pacific" for 4 weeks
|
|
23
|
+
const events = expandRRule(
|
|
24
|
+
"FREQ=WEEKLY;COUNT=4;BYDAY=TU",
|
|
25
|
+
"2026-02-17T14:00:00",
|
|
26
|
+
60, // 60-minute duration
|
|
27
|
+
"America/Los_Angeles", // IANA timezone (DST-aware)
|
|
28
|
+
);
|
|
29
|
+
// events = [{ start: "2026-02-17T22:00:00+00:00", end: "2026-02-17T23:00:00+00:00" }, ...]
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Merge Multi-Calendar Availability
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { mergeAvailability } from "@temporal-cortex/truth-engine";
|
|
36
|
+
|
|
37
|
+
const availability = mergeAvailability(
|
|
38
|
+
[
|
|
39
|
+
{ stream_id: "google", events: [{ start: "2026-03-16T09:00:00Z", end: "2026-03-16T10:00:00Z" }] },
|
|
40
|
+
{ stream_id: "outlook", events: [{ start: "2026-03-16T14:00:00Z", end: "2026-03-16T15:00:00Z" }] },
|
|
41
|
+
],
|
|
42
|
+
"2026-03-16T08:00:00Z",
|
|
43
|
+
"2026-03-16T17:00:00Z",
|
|
44
|
+
true, // opaque mode — hides which calendar each block came from
|
|
45
|
+
);
|
|
46
|
+
// availability.busy = [{ start, end, source_count: 0 }, ...]
|
|
47
|
+
// availability.free = [{ start, end, duration_minutes }, ...]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Find Conflicts
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { findConflicts } from "@temporal-cortex/truth-engine";
|
|
54
|
+
|
|
55
|
+
const teamA = [{ start: "2026-02-17T14:00:00Z", end: "2026-02-17T15:00:00Z" }];
|
|
56
|
+
const teamB = [{ start: "2026-02-17T14:30:00Z", end: "2026-02-17T15:30:00Z" }];
|
|
57
|
+
|
|
58
|
+
const conflicts = findConflicts(teamA, teamB);
|
|
59
|
+
// [{ event_a: {...}, event_b: {...}, overlap_minutes: 30 }]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Find Free Slots
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { findFreeSlots } from "@temporal-cortex/truth-engine";
|
|
66
|
+
|
|
67
|
+
const busyEvents = [
|
|
68
|
+
{ start: "2026-02-17T09:00:00Z", end: "2026-02-17T10:00:00Z" },
|
|
69
|
+
{ start: "2026-02-17T11:00:00Z", end: "2026-02-17T12:00:00Z" },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const slots = findFreeSlots(busyEvents, "2026-02-17T08:00:00", "2026-02-17T13:00:00");
|
|
73
|
+
// [{ start, end, duration_minutes: 60 }, { ... }, { ... }]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Find First Available Slot Across Calendars
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { findFirstFreeAcross } from "@temporal-cortex/truth-engine";
|
|
80
|
+
|
|
81
|
+
const slot = findFirstFreeAcross(
|
|
82
|
+
[
|
|
83
|
+
{ stream_id: "google", events: [{ start: "2026-03-16T09:00:00Z", end: "2026-03-16T10:00:00Z" }] },
|
|
84
|
+
{ stream_id: "outlook", events: [{ start: "2026-03-16T10:00:00Z", end: "2026-03-16T11:00:00Z" }] },
|
|
85
|
+
],
|
|
86
|
+
"2026-03-16T08:00:00Z",
|
|
87
|
+
"2026-03-16T17:00:00Z",
|
|
88
|
+
30, // minimum 30-minute slot
|
|
89
|
+
);
|
|
90
|
+
// { start, end, duration_minutes }
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API
|
|
94
|
+
|
|
95
|
+
### `expandRRule(rrule, dtstart, durationMinutes, timezone, until?, maxCount?): TimeRange[]`
|
|
96
|
+
|
|
97
|
+
Expand an RFC 5545 RRULE into concrete event instances. Supports FREQ, BYDAY, BYSETPOS, BYMONTHDAY, COUNT, UNTIL, EXDATE. DST-aware — events at 14:00 Pacific stay at 14:00 Pacific across transitions.
|
|
98
|
+
|
|
99
|
+
### `findConflicts(eventsA, eventsB): Conflict[]`
|
|
100
|
+
|
|
101
|
+
Find all pairwise overlaps between two event lists. Adjacent events (end === start) are not conflicts.
|
|
102
|
+
|
|
103
|
+
### `findFreeSlots(events, windowStart, windowEnd): FreeSlot[]`
|
|
104
|
+
|
|
105
|
+
Find free time slots within a window, given a list of busy events.
|
|
106
|
+
|
|
107
|
+
### `mergeAvailability(streams, windowStart, windowEnd, opaque?): UnifiedAvailability`
|
|
108
|
+
|
|
109
|
+
Merge N event streams into a unified busy/free view. In opaque mode (default), source counts are hidden for privacy.
|
|
110
|
+
|
|
111
|
+
### `findFirstFreeAcross(streams, windowStart, windowEnd, minDurationMinutes): FreeSlot | null`
|
|
112
|
+
|
|
113
|
+
Find the first free slot of at least `minDurationMinutes` across all merged streams. Returns `null` if no qualifying slot exists.
|
|
114
|
+
|
|
115
|
+
## Types
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
interface TimeRange { start: string; end: string }
|
|
119
|
+
interface Conflict { event_a: TimeRange; event_b: TimeRange; overlap_minutes: number }
|
|
120
|
+
interface FreeSlot { start: string; end: string; duration_minutes: number }
|
|
121
|
+
interface EventStream { stream_id: string; events: TimeRange[] }
|
|
122
|
+
interface BusyBlock { start: string; end: string; source_count: number }
|
|
123
|
+
interface UnifiedAvailability { busy: BusyBlock[]; free: FreeSlot[]; window_start: string; window_end: string; privacy: string }
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Build from Source
|
|
127
|
+
|
|
128
|
+
This package requires the WASM artifacts to be built from the Rust crate first:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# From the monorepo root:
|
|
132
|
+
|
|
133
|
+
# 1. Build the WASM binary
|
|
134
|
+
cargo build -p truth-engine-wasm --target wasm32-unknown-unknown --release
|
|
135
|
+
|
|
136
|
+
# 2. Generate Node.js bindings
|
|
137
|
+
wasm-bindgen --target nodejs \
|
|
138
|
+
--out-dir packages/truth-engine-js/wasm/ \
|
|
139
|
+
target/wasm32-unknown-unknown/release/truth_engine_wasm.wasm
|
|
140
|
+
|
|
141
|
+
# 3. Rename for ESM/CJS compatibility
|
|
142
|
+
mv packages/truth-engine-js/wasm/truth_engine_wasm.js packages/truth-engine-js/wasm/truth_engine_wasm.cjs
|
|
143
|
+
|
|
144
|
+
# 4. Build TypeScript
|
|
145
|
+
pnpm --filter @temporal-cortex/truth-engine build
|
|
146
|
+
|
|
147
|
+
# 5. Run tests
|
|
148
|
+
pnpm --filter @temporal-cortex/truth-engine test
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Architecture
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
src/index.ts ← Public API, loads WASM via createRequire
|
|
155
|
+
wasm/truth_engine_wasm.cjs ← wasm-bindgen generated CommonJS bindings
|
|
156
|
+
wasm/truth_engine_wasm.wasm ← Compiled WASM binary from truth-engine (Rust)
|
|
157
|
+
wasm/truth_engine_wasm.d.ts ← TypeScript type declarations for WASM exports
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The package uses `createRequire(import.meta.url)` to load the CommonJS WASM bindings from an ESM context. This bridges the module system mismatch since `wasm-bindgen --target nodejs` generates CommonJS but the package uses `"type": "module"`.
|
|
161
|
+
|
|
162
|
+
## Testing
|
|
163
|
+
|
|
164
|
+
13 tests covering RRULE expansion (8), conflict detection (3), and free/busy computation (2):
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
pnpm --filter @temporal-cortex/truth-engine test
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT OR Apache-2.0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export interface TimeRange {
|
|
2
|
+
start: string;
|
|
3
|
+
end: string;
|
|
4
|
+
}
|
|
5
|
+
export interface Conflict {
|
|
6
|
+
event_a: TimeRange;
|
|
7
|
+
event_b: TimeRange;
|
|
8
|
+
overlap_minutes: number;
|
|
9
|
+
}
|
|
10
|
+
export interface FreeSlot {
|
|
11
|
+
start: string;
|
|
12
|
+
end: string;
|
|
13
|
+
duration_minutes: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Expand an RFC 5545 RRULE into concrete event instances.
|
|
17
|
+
*
|
|
18
|
+
* @param rrule - RFC 5545 recurrence rule (e.g., "FREQ=DAILY;COUNT=3")
|
|
19
|
+
* @param dtstart - Local datetime for the first occurrence (e.g., "2026-02-17T14:00:00")
|
|
20
|
+
* @param durationMinutes - Duration of each instance in minutes
|
|
21
|
+
* @param timezone - IANA timezone (e.g., "America/Los_Angeles")
|
|
22
|
+
* @param until - Optional end boundary (local datetime string)
|
|
23
|
+
* @param maxCount - Optional maximum number of instances to generate
|
|
24
|
+
* @returns Array of {start, end} objects with RFC 3339 datetime strings
|
|
25
|
+
*/
|
|
26
|
+
export declare function expandRRule(rrule: string, dtstart: string, durationMinutes: number, timezone: string, until?: string, maxCount?: number): TimeRange[];
|
|
27
|
+
/**
|
|
28
|
+
* Find all pairwise conflicts (overlapping time ranges) between two event lists.
|
|
29
|
+
*
|
|
30
|
+
* @param eventsA - First list of events
|
|
31
|
+
* @param eventsB - Second list of events
|
|
32
|
+
* @returns Array of conflict objects with event_a, event_b, and overlap_minutes
|
|
33
|
+
*/
|
|
34
|
+
export declare function findConflicts(eventsA: TimeRange[], eventsB: TimeRange[]): Conflict[];
|
|
35
|
+
/**
|
|
36
|
+
* Find free time slots within a given window, given a list of busy events.
|
|
37
|
+
*
|
|
38
|
+
* @param events - List of busy events
|
|
39
|
+
* @param windowStart - Start of the search window (ISO 8601 datetime)
|
|
40
|
+
* @param windowEnd - End of the search window (ISO 8601 datetime)
|
|
41
|
+
* @returns Array of free slot objects with start, end, and duration_minutes
|
|
42
|
+
*/
|
|
43
|
+
export declare function findFreeSlots(events: TimeRange[], windowStart: string, windowEnd: string): FreeSlot[];
|
|
44
|
+
export interface EventStream {
|
|
45
|
+
stream_id: string;
|
|
46
|
+
events: TimeRange[];
|
|
47
|
+
}
|
|
48
|
+
export interface BusyBlock {
|
|
49
|
+
start: string;
|
|
50
|
+
end: string;
|
|
51
|
+
source_count: number;
|
|
52
|
+
}
|
|
53
|
+
export interface UnifiedAvailability {
|
|
54
|
+
busy: BusyBlock[];
|
|
55
|
+
free: FreeSlot[];
|
|
56
|
+
window_start: string;
|
|
57
|
+
window_end: string;
|
|
58
|
+
privacy: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Merge N event streams into unified availability within a time window.
|
|
62
|
+
*
|
|
63
|
+
* This is the core of the "Unified Availability Graph" — it computes a
|
|
64
|
+
* single source of truth for a user's availability across all their calendars.
|
|
65
|
+
*
|
|
66
|
+
* @param streams - Array of event streams (from different calendars/providers)
|
|
67
|
+
* @param windowStart - Start of the analysis window (ISO 8601 datetime)
|
|
68
|
+
* @param windowEnd - End of the analysis window (ISO 8601 datetime)
|
|
69
|
+
* @param opaque - If true, hide source counts in busy blocks (privacy mode). Default: true.
|
|
70
|
+
* @returns Unified availability with busy blocks and free slots
|
|
71
|
+
*/
|
|
72
|
+
export declare function mergeAvailability(streams: EventStream[], windowStart: string, windowEnd: string, opaque?: boolean): UnifiedAvailability;
|
|
73
|
+
/**
|
|
74
|
+
* Find the first free slot of at least `minDurationMinutes` across N merged
|
|
75
|
+
* event streams.
|
|
76
|
+
*
|
|
77
|
+
* @param streams - Array of event streams
|
|
78
|
+
* @param windowStart - Start of the search window (ISO 8601 datetime)
|
|
79
|
+
* @param windowEnd - End of the search window (ISO 8601 datetime)
|
|
80
|
+
* @param minDurationMinutes - Minimum slot duration in minutes
|
|
81
|
+
* @returns The first qualifying free slot, or null if none found
|
|
82
|
+
*/
|
|
83
|
+
export declare function findFirstFreeAcross(streams: EventStream[], windowStart: string, windowEnd: string, minDurationMinutes: number): FreeSlot | null;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// @temporal-cortex/truth-engine — WASM-powered RRULE expansion, conflict
|
|
2
|
+
// detection, and free/busy computation for Node.js.
|
|
3
|
+
//
|
|
4
|
+
// This module loads the WASM binary compiled from the truth-engine-wasm Rust
|
|
5
|
+
// crate. The WASM bindings are generated by wasm-bindgen as CommonJS (.cjs),
|
|
6
|
+
// but this package uses ESM ("type": "module" in package.json). We bridge the
|
|
7
|
+
// two module systems using Node's createRequire().
|
|
8
|
+
//
|
|
9
|
+
// Build chain:
|
|
10
|
+
// truth-engine (Rust) -> truth-engine-wasm (wasm-bindgen) -> truth-engine-js (this wrapper)
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
// Load the WASM-generated Node.js bindings (.cjs for CommonJS/ESM compat)
|
|
14
|
+
const wasm = require("../wasm/truth_engine_wasm.cjs");
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Public API
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
/**
|
|
19
|
+
* Expand an RFC 5545 RRULE into concrete event instances.
|
|
20
|
+
*
|
|
21
|
+
* @param rrule - RFC 5545 recurrence rule (e.g., "FREQ=DAILY;COUNT=3")
|
|
22
|
+
* @param dtstart - Local datetime for the first occurrence (e.g., "2026-02-17T14:00:00")
|
|
23
|
+
* @param durationMinutes - Duration of each instance in minutes
|
|
24
|
+
* @param timezone - IANA timezone (e.g., "America/Los_Angeles")
|
|
25
|
+
* @param until - Optional end boundary (local datetime string)
|
|
26
|
+
* @param maxCount - Optional maximum number of instances to generate
|
|
27
|
+
* @returns Array of {start, end} objects with RFC 3339 datetime strings
|
|
28
|
+
*/
|
|
29
|
+
export function expandRRule(rrule, dtstart, durationMinutes, timezone, until, maxCount) {
|
|
30
|
+
const json = wasm.expandRRule(rrule, dtstart, durationMinutes, timezone, until ?? undefined, maxCount ?? undefined);
|
|
31
|
+
return JSON.parse(json);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Find all pairwise conflicts (overlapping time ranges) between two event lists.
|
|
35
|
+
*
|
|
36
|
+
* @param eventsA - First list of events
|
|
37
|
+
* @param eventsB - Second list of events
|
|
38
|
+
* @returns Array of conflict objects with event_a, event_b, and overlap_minutes
|
|
39
|
+
*/
|
|
40
|
+
export function findConflicts(eventsA, eventsB) {
|
|
41
|
+
const json = wasm.findConflicts(JSON.stringify(eventsA), JSON.stringify(eventsB));
|
|
42
|
+
return JSON.parse(json);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Find free time slots within a given window, given a list of busy events.
|
|
46
|
+
*
|
|
47
|
+
* @param events - List of busy events
|
|
48
|
+
* @param windowStart - Start of the search window (ISO 8601 datetime)
|
|
49
|
+
* @param windowEnd - End of the search window (ISO 8601 datetime)
|
|
50
|
+
* @returns Array of free slot objects with start, end, and duration_minutes
|
|
51
|
+
*/
|
|
52
|
+
export function findFreeSlots(events, windowStart, windowEnd) {
|
|
53
|
+
const json = wasm.findFreeSlots(JSON.stringify(events), windowStart, windowEnd);
|
|
54
|
+
return JSON.parse(json);
|
|
55
|
+
}
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Multi-stream availability API
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Merge N event streams into unified availability within a time window.
|
|
61
|
+
*
|
|
62
|
+
* This is the core of the "Unified Availability Graph" — it computes a
|
|
63
|
+
* single source of truth for a user's availability across all their calendars.
|
|
64
|
+
*
|
|
65
|
+
* @param streams - Array of event streams (from different calendars/providers)
|
|
66
|
+
* @param windowStart - Start of the analysis window (ISO 8601 datetime)
|
|
67
|
+
* @param windowEnd - End of the analysis window (ISO 8601 datetime)
|
|
68
|
+
* @param opaque - If true, hide source counts in busy blocks (privacy mode). Default: true.
|
|
69
|
+
* @returns Unified availability with busy blocks and free slots
|
|
70
|
+
*/
|
|
71
|
+
export function mergeAvailability(streams, windowStart, windowEnd, opaque = true) {
|
|
72
|
+
const json = wasm.mergeAvailability(JSON.stringify(streams), windowStart, windowEnd, opaque);
|
|
73
|
+
return JSON.parse(json);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Find the first free slot of at least `minDurationMinutes` across N merged
|
|
77
|
+
* event streams.
|
|
78
|
+
*
|
|
79
|
+
* @param streams - Array of event streams
|
|
80
|
+
* @param windowStart - Start of the search window (ISO 8601 datetime)
|
|
81
|
+
* @param windowEnd - End of the search window (ISO 8601 datetime)
|
|
82
|
+
* @param minDurationMinutes - Minimum slot duration in minutes
|
|
83
|
+
* @returns The first qualifying free slot, or null if none found
|
|
84
|
+
*/
|
|
85
|
+
export function findFirstFreeAcross(streams, windowStart, windowEnd, minDurationMinutes) {
|
|
86
|
+
const json = wasm.findFirstFreeAcross(JSON.stringify(streams), windowStart, windowEnd, minDurationMinutes);
|
|
87
|
+
return JSON.parse(json);
|
|
88
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@temporal-cortex/truth-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Truth Engine — deterministic RRULE expansion, conflict detection, free/busy for AI calendar agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"wasm"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"rrule",
|
|
14
|
+
"calendar",
|
|
15
|
+
"icalendar",
|
|
16
|
+
"recurrence",
|
|
17
|
+
"wasm"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT OR Apache-2.0",
|
|
20
|
+
"author": "Billy Lui",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/billylui/temporal-cortex-core.git",
|
|
24
|
+
"directory": "packages/truth-engine-js"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/billylui/temporal-cortex-core",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/billylui/temporal-cortex-core/issues"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/node": "^20",
|
|
32
|
+
"typescript": "^5",
|
|
33
|
+
"vitest": "^3"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/* @ts-self-types="./truth_engine_wasm.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Expand an RRULE string into concrete datetime instances.
|
|
5
|
+
*
|
|
6
|
+
* Returns a JSON string containing an array of `{start, end}` objects with
|
|
7
|
+
* RFC 3339 datetime strings.
|
|
8
|
+
*
|
|
9
|
+
* # Arguments
|
|
10
|
+
* - `rrule` -- RFC 5545 RRULE string (e.g., "FREQ=WEEKLY;BYDAY=TU,TH")
|
|
11
|
+
* - `dtstart` -- Local datetime string (e.g., "2026-02-17T14:00:00")
|
|
12
|
+
* - `duration_minutes` -- Duration of each instance in minutes
|
|
13
|
+
* - `timezone` -- IANA timezone (e.g., "America/Los_Angeles")
|
|
14
|
+
* - `until` -- Optional end boundary for expansion (local datetime string)
|
|
15
|
+
* - `max_count` -- Optional maximum number of instances
|
|
16
|
+
* @param {string} rrule
|
|
17
|
+
* @param {string} dtstart
|
|
18
|
+
* @param {number} duration_minutes
|
|
19
|
+
* @param {string} timezone
|
|
20
|
+
* @param {string | null} [until]
|
|
21
|
+
* @param {number | null} [max_count]
|
|
22
|
+
* @returns {string}
|
|
23
|
+
*/
|
|
24
|
+
function expandRRule(rrule, dtstart, duration_minutes, timezone, until, max_count) {
|
|
25
|
+
let deferred6_0;
|
|
26
|
+
let deferred6_1;
|
|
27
|
+
try {
|
|
28
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
29
|
+
const ptr0 = passStringToWasm0(rrule, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
30
|
+
const len0 = WASM_VECTOR_LEN;
|
|
31
|
+
const ptr1 = passStringToWasm0(dtstart, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
32
|
+
const len1 = WASM_VECTOR_LEN;
|
|
33
|
+
const ptr2 = passStringToWasm0(timezone, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
34
|
+
const len2 = WASM_VECTOR_LEN;
|
|
35
|
+
var ptr3 = isLikeNone(until) ? 0 : passStringToWasm0(until, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
36
|
+
var len3 = WASM_VECTOR_LEN;
|
|
37
|
+
wasm.expandRRule(retptr, ptr0, len0, ptr1, len1, duration_minutes, ptr2, len2, ptr3, len3, isLikeNone(max_count) ? 0x100000001 : (max_count) >>> 0);
|
|
38
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
39
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
40
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
41
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
42
|
+
var ptr5 = r0;
|
|
43
|
+
var len5 = r1;
|
|
44
|
+
if (r3) {
|
|
45
|
+
ptr5 = 0; len5 = 0;
|
|
46
|
+
throw takeObject(r2);
|
|
47
|
+
}
|
|
48
|
+
deferred6_0 = ptr5;
|
|
49
|
+
deferred6_1 = len5;
|
|
50
|
+
return getStringFromWasm0(ptr5, len5);
|
|
51
|
+
} finally {
|
|
52
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
53
|
+
wasm.__wbindgen_export3(deferred6_0, deferred6_1, 1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.expandRRule = expandRRule;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Find all pairwise conflicts (overlapping time ranges) between two event lists.
|
|
60
|
+
*
|
|
61
|
+
* Both arguments must be JSON arrays of `{start, end}` objects with ISO 8601
|
|
62
|
+
* datetime strings. Returns a JSON string containing an array of conflict objects,
|
|
63
|
+
* each with `event_a`, `event_b`, and `overlap_minutes`.
|
|
64
|
+
* @param {string} events_a_json
|
|
65
|
+
* @param {string} events_b_json
|
|
66
|
+
* @returns {string}
|
|
67
|
+
*/
|
|
68
|
+
function findConflicts(events_a_json, events_b_json) {
|
|
69
|
+
let deferred4_0;
|
|
70
|
+
let deferred4_1;
|
|
71
|
+
try {
|
|
72
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
73
|
+
const ptr0 = passStringToWasm0(events_a_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
74
|
+
const len0 = WASM_VECTOR_LEN;
|
|
75
|
+
const ptr1 = passStringToWasm0(events_b_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
76
|
+
const len1 = WASM_VECTOR_LEN;
|
|
77
|
+
wasm.findConflicts(retptr, ptr0, len0, ptr1, len1);
|
|
78
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
79
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
80
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
81
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
82
|
+
var ptr3 = r0;
|
|
83
|
+
var len3 = r1;
|
|
84
|
+
if (r3) {
|
|
85
|
+
ptr3 = 0; len3 = 0;
|
|
86
|
+
throw takeObject(r2);
|
|
87
|
+
}
|
|
88
|
+
deferred4_0 = ptr3;
|
|
89
|
+
deferred4_1 = len3;
|
|
90
|
+
return getStringFromWasm0(ptr3, len3);
|
|
91
|
+
} finally {
|
|
92
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
93
|
+
wasm.__wbindgen_export3(deferred4_0, deferred4_1, 1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.findConflicts = findConflicts;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Find the first free slot of at least `min_duration_minutes` across N merged
|
|
100
|
+
* event streams.
|
|
101
|
+
*
|
|
102
|
+
* `streams_json` must be a JSON array of `{stream_id, events: [{start, end}]}`.
|
|
103
|
+
* Returns a JSON string with `{start, end, duration_minutes}` or `null`.
|
|
104
|
+
* @param {string} streams_json
|
|
105
|
+
* @param {string} window_start
|
|
106
|
+
* @param {string} window_end
|
|
107
|
+
* @param {bigint} min_duration_minutes
|
|
108
|
+
* @returns {string}
|
|
109
|
+
*/
|
|
110
|
+
function findFirstFreeAcross(streams_json, window_start, window_end, min_duration_minutes) {
|
|
111
|
+
let deferred5_0;
|
|
112
|
+
let deferred5_1;
|
|
113
|
+
try {
|
|
114
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
115
|
+
const ptr0 = passStringToWasm0(streams_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
116
|
+
const len0 = WASM_VECTOR_LEN;
|
|
117
|
+
const ptr1 = passStringToWasm0(window_start, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
118
|
+
const len1 = WASM_VECTOR_LEN;
|
|
119
|
+
const ptr2 = passStringToWasm0(window_end, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
120
|
+
const len2 = WASM_VECTOR_LEN;
|
|
121
|
+
wasm.findFirstFreeAcross(retptr, ptr0, len0, ptr1, len1, ptr2, len2, min_duration_minutes);
|
|
122
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
123
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
124
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
125
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
126
|
+
var ptr4 = r0;
|
|
127
|
+
var len4 = r1;
|
|
128
|
+
if (r3) {
|
|
129
|
+
ptr4 = 0; len4 = 0;
|
|
130
|
+
throw takeObject(r2);
|
|
131
|
+
}
|
|
132
|
+
deferred5_0 = ptr4;
|
|
133
|
+
deferred5_1 = len4;
|
|
134
|
+
return getStringFromWasm0(ptr4, len4);
|
|
135
|
+
} finally {
|
|
136
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
137
|
+
wasm.__wbindgen_export3(deferred5_0, deferred5_1, 1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.findFirstFreeAcross = findFirstFreeAcross;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Find free time slots within a given time window, given a list of busy events.
|
|
144
|
+
*
|
|
145
|
+
* `events_json` must be a JSON array of `{start, end}` objects. `window_start`
|
|
146
|
+
* and `window_end` are ISO 8601 datetime strings. Returns a JSON string containing
|
|
147
|
+
* an array of `{start, end, duration_minutes}` objects.
|
|
148
|
+
* @param {string} events_json
|
|
149
|
+
* @param {string} window_start
|
|
150
|
+
* @param {string} window_end
|
|
151
|
+
* @returns {string}
|
|
152
|
+
*/
|
|
153
|
+
function findFreeSlots(events_json, window_start, window_end) {
|
|
154
|
+
let deferred5_0;
|
|
155
|
+
let deferred5_1;
|
|
156
|
+
try {
|
|
157
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
158
|
+
const ptr0 = passStringToWasm0(events_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
159
|
+
const len0 = WASM_VECTOR_LEN;
|
|
160
|
+
const ptr1 = passStringToWasm0(window_start, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
161
|
+
const len1 = WASM_VECTOR_LEN;
|
|
162
|
+
const ptr2 = passStringToWasm0(window_end, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
163
|
+
const len2 = WASM_VECTOR_LEN;
|
|
164
|
+
wasm.findFreeSlots(retptr, ptr0, len0, ptr1, len1, ptr2, len2);
|
|
165
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
166
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
167
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
168
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
169
|
+
var ptr4 = r0;
|
|
170
|
+
var len4 = r1;
|
|
171
|
+
if (r3) {
|
|
172
|
+
ptr4 = 0; len4 = 0;
|
|
173
|
+
throw takeObject(r2);
|
|
174
|
+
}
|
|
175
|
+
deferred5_0 = ptr4;
|
|
176
|
+
deferred5_1 = len4;
|
|
177
|
+
return getStringFromWasm0(ptr4, len4);
|
|
178
|
+
} finally {
|
|
179
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
180
|
+
wasm.__wbindgen_export3(deferred5_0, deferred5_1, 1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.findFreeSlots = findFreeSlots;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Merge N event streams into unified availability within a time window.
|
|
187
|
+
*
|
|
188
|
+
* `streams_json` must be a JSON array of `{stream_id, events: [{start, end}]}`.
|
|
189
|
+
* `window_start` and `window_end` are ISO 8601 datetime strings.
|
|
190
|
+
* `opaque` controls privacy: true = hide source counts, false = show them.
|
|
191
|
+
*
|
|
192
|
+
* Returns a JSON string with `{busy, free, window_start, window_end, privacy}`.
|
|
193
|
+
* @param {string} streams_json
|
|
194
|
+
* @param {string} window_start
|
|
195
|
+
* @param {string} window_end
|
|
196
|
+
* @param {boolean} opaque
|
|
197
|
+
* @returns {string}
|
|
198
|
+
*/
|
|
199
|
+
function mergeAvailability(streams_json, window_start, window_end, opaque) {
|
|
200
|
+
let deferred5_0;
|
|
201
|
+
let deferred5_1;
|
|
202
|
+
try {
|
|
203
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
204
|
+
const ptr0 = passStringToWasm0(streams_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
205
|
+
const len0 = WASM_VECTOR_LEN;
|
|
206
|
+
const ptr1 = passStringToWasm0(window_start, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
207
|
+
const len1 = WASM_VECTOR_LEN;
|
|
208
|
+
const ptr2 = passStringToWasm0(window_end, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
209
|
+
const len2 = WASM_VECTOR_LEN;
|
|
210
|
+
wasm.mergeAvailability(retptr, ptr0, len0, ptr1, len1, ptr2, len2, opaque);
|
|
211
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
212
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
213
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
214
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
215
|
+
var ptr4 = r0;
|
|
216
|
+
var len4 = r1;
|
|
217
|
+
if (r3) {
|
|
218
|
+
ptr4 = 0; len4 = 0;
|
|
219
|
+
throw takeObject(r2);
|
|
220
|
+
}
|
|
221
|
+
deferred5_0 = ptr4;
|
|
222
|
+
deferred5_1 = len4;
|
|
223
|
+
return getStringFromWasm0(ptr4, len4);
|
|
224
|
+
} finally {
|
|
225
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
226
|
+
wasm.__wbindgen_export3(deferred5_0, deferred5_1, 1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
exports.mergeAvailability = mergeAvailability;
|
|
230
|
+
|
|
231
|
+
function __wbg_get_imports() {
|
|
232
|
+
const import0 = {
|
|
233
|
+
__proto__: null,
|
|
234
|
+
__wbg___wbindgen_throw_be289d5034ed271b: function(arg0, arg1) {
|
|
235
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
236
|
+
},
|
|
237
|
+
__wbg_getTimezoneOffset_81776d10a4ec18a8: function(arg0) {
|
|
238
|
+
const ret = getObject(arg0).getTimezoneOffset();
|
|
239
|
+
return ret;
|
|
240
|
+
},
|
|
241
|
+
__wbg_new_245cd5c49157e602: function(arg0) {
|
|
242
|
+
const ret = new Date(getObject(arg0));
|
|
243
|
+
return addHeapObject(ret);
|
|
244
|
+
},
|
|
245
|
+
__wbg_new_with_year_month_day_hr_min_sec_f82362c71c4dfc23: function(arg0, arg1, arg2, arg3, arg4, arg5) {
|
|
246
|
+
const ret = new Date(arg0 >>> 0, arg1, arg2, arg3, arg4, arg5);
|
|
247
|
+
return addHeapObject(ret);
|
|
248
|
+
},
|
|
249
|
+
__wbindgen_cast_0000000000000001: function(arg0) {
|
|
250
|
+
// Cast intrinsic for `F64 -> Externref`.
|
|
251
|
+
const ret = arg0;
|
|
252
|
+
return addHeapObject(ret);
|
|
253
|
+
},
|
|
254
|
+
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
255
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
256
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
257
|
+
return addHeapObject(ret);
|
|
258
|
+
},
|
|
259
|
+
__wbindgen_object_drop_ref: function(arg0) {
|
|
260
|
+
takeObject(arg0);
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
return {
|
|
264
|
+
__proto__: null,
|
|
265
|
+
"./truth_engine_wasm_bg.js": import0,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function addHeapObject(obj) {
|
|
270
|
+
if (heap_next === heap.length) heap.push(heap.length + 1);
|
|
271
|
+
const idx = heap_next;
|
|
272
|
+
heap_next = heap[idx];
|
|
273
|
+
|
|
274
|
+
heap[idx] = obj;
|
|
275
|
+
return idx;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function dropObject(idx) {
|
|
279
|
+
if (idx < 132) return;
|
|
280
|
+
heap[idx] = heap_next;
|
|
281
|
+
heap_next = idx;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let cachedDataViewMemory0 = null;
|
|
285
|
+
function getDataViewMemory0() {
|
|
286
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
287
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
288
|
+
}
|
|
289
|
+
return cachedDataViewMemory0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function getStringFromWasm0(ptr, len) {
|
|
293
|
+
ptr = ptr >>> 0;
|
|
294
|
+
return decodeText(ptr, len);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let cachedUint8ArrayMemory0 = null;
|
|
298
|
+
function getUint8ArrayMemory0() {
|
|
299
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
300
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
301
|
+
}
|
|
302
|
+
return cachedUint8ArrayMemory0;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function getObject(idx) { return heap[idx]; }
|
|
306
|
+
|
|
307
|
+
let heap = new Array(128).fill(undefined);
|
|
308
|
+
heap.push(undefined, null, true, false);
|
|
309
|
+
|
|
310
|
+
let heap_next = heap.length;
|
|
311
|
+
|
|
312
|
+
function isLikeNone(x) {
|
|
313
|
+
return x === undefined || x === null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
317
|
+
if (realloc === undefined) {
|
|
318
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
319
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
320
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
321
|
+
WASM_VECTOR_LEN = buf.length;
|
|
322
|
+
return ptr;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
let len = arg.length;
|
|
326
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
327
|
+
|
|
328
|
+
const mem = getUint8ArrayMemory0();
|
|
329
|
+
|
|
330
|
+
let offset = 0;
|
|
331
|
+
|
|
332
|
+
for (; offset < len; offset++) {
|
|
333
|
+
const code = arg.charCodeAt(offset);
|
|
334
|
+
if (code > 0x7F) break;
|
|
335
|
+
mem[ptr + offset] = code;
|
|
336
|
+
}
|
|
337
|
+
if (offset !== len) {
|
|
338
|
+
if (offset !== 0) {
|
|
339
|
+
arg = arg.slice(offset);
|
|
340
|
+
}
|
|
341
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
342
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
343
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
344
|
+
|
|
345
|
+
offset += ret.written;
|
|
346
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
WASM_VECTOR_LEN = offset;
|
|
350
|
+
return ptr;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function takeObject(idx) {
|
|
354
|
+
const ret = getObject(idx);
|
|
355
|
+
dropObject(idx);
|
|
356
|
+
return ret;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
360
|
+
cachedTextDecoder.decode();
|
|
361
|
+
function decodeText(ptr, len) {
|
|
362
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const cachedTextEncoder = new TextEncoder();
|
|
366
|
+
|
|
367
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
368
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
369
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
370
|
+
view.set(buf);
|
|
371
|
+
return {
|
|
372
|
+
read: arg.length,
|
|
373
|
+
written: buf.length
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
let WASM_VECTOR_LEN = 0;
|
|
379
|
+
|
|
380
|
+
const wasmPath = `${__dirname}/truth_engine_wasm_bg.wasm`;
|
|
381
|
+
const wasmBytes = require('fs').readFileSync(wasmPath);
|
|
382
|
+
const wasmModule = new WebAssembly.Module(wasmBytes);
|
|
383
|
+
const wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Expand an RRULE string into concrete datetime instances.
|
|
6
|
+
*
|
|
7
|
+
* Returns a JSON string containing an array of `{start, end}` objects with
|
|
8
|
+
* RFC 3339 datetime strings.
|
|
9
|
+
*
|
|
10
|
+
* # Arguments
|
|
11
|
+
* - `rrule` -- RFC 5545 RRULE string (e.g., "FREQ=WEEKLY;BYDAY=TU,TH")
|
|
12
|
+
* - `dtstart` -- Local datetime string (e.g., "2026-02-17T14:00:00")
|
|
13
|
+
* - `duration_minutes` -- Duration of each instance in minutes
|
|
14
|
+
* - `timezone` -- IANA timezone (e.g., "America/Los_Angeles")
|
|
15
|
+
* - `until` -- Optional end boundary for expansion (local datetime string)
|
|
16
|
+
* - `max_count` -- Optional maximum number of instances
|
|
17
|
+
*/
|
|
18
|
+
export function expandRRule(rrule: string, dtstart: string, duration_minutes: number, timezone: string, until?: string | null, max_count?: number | null): string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Find all pairwise conflicts (overlapping time ranges) between two event lists.
|
|
22
|
+
*
|
|
23
|
+
* Both arguments must be JSON arrays of `{start, end}` objects with ISO 8601
|
|
24
|
+
* datetime strings. Returns a JSON string containing an array of conflict objects,
|
|
25
|
+
* each with `event_a`, `event_b`, and `overlap_minutes`.
|
|
26
|
+
*/
|
|
27
|
+
export function findConflicts(events_a_json: string, events_b_json: string): string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the first free slot of at least `min_duration_minutes` across N merged
|
|
31
|
+
* event streams.
|
|
32
|
+
*
|
|
33
|
+
* `streams_json` must be a JSON array of `{stream_id, events: [{start, end}]}`.
|
|
34
|
+
* Returns a JSON string with `{start, end, duration_minutes}` or `null`.
|
|
35
|
+
*/
|
|
36
|
+
export function findFirstFreeAcross(streams_json: string, window_start: string, window_end: string, min_duration_minutes: bigint): string;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Find free time slots within a given time window, given a list of busy events.
|
|
40
|
+
*
|
|
41
|
+
* `events_json` must be a JSON array of `{start, end}` objects. `window_start`
|
|
42
|
+
* and `window_end` are ISO 8601 datetime strings. Returns a JSON string containing
|
|
43
|
+
* an array of `{start, end, duration_minutes}` objects.
|
|
44
|
+
*/
|
|
45
|
+
export function findFreeSlots(events_json: string, window_start: string, window_end: string): string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Merge N event streams into unified availability within a time window.
|
|
49
|
+
*
|
|
50
|
+
* `streams_json` must be a JSON array of `{stream_id, events: [{start, end}]}`.
|
|
51
|
+
* `window_start` and `window_end` are ISO 8601 datetime strings.
|
|
52
|
+
* `opaque` controls privacy: true = hide source counts, false = show them.
|
|
53
|
+
*
|
|
54
|
+
* Returns a JSON string with `{busy, free, window_start, window_end, privacy}`.
|
|
55
|
+
*/
|
|
56
|
+
export function mergeAvailability(streams_json: string, window_start: string, window_end: string, opaque: boolean): string;
|
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
export const memory: WebAssembly.Memory;
|
|
4
|
+
export const expandRRule: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
|
|
5
|
+
export const findConflicts: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
6
|
+
export const findFirstFreeAcross: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: bigint) => void;
|
|
7
|
+
export const findFreeSlots: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
8
|
+
export const mergeAvailability: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
9
|
+
export const __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
10
|
+
export const __wbindgen_export: (a: number, b: number) => number;
|
|
11
|
+
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
12
|
+
export const __wbindgen_export3: (a: number, b: number, c: number) => void;
|