aweshare 0.7.0 → 0.7.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.
- package/README.ai.md +1 -0
- package/README.md +28 -2
- package/apps/agent/dist/config.d.ts +1 -1
- package/apps/agent/dist/config.js +11 -0
- package/apps/agent/dist/config.js.map +1 -1
- package/apps/agent/dist/connection.js +3 -29
- package/apps/agent/dist/connection.js.map +1 -1
- package/apps/agent/dist/hub.d.ts +6 -0
- package/apps/agent/dist/hub.js.map +1 -1
- package/apps/agent/dist/table.d.ts +11 -1
- package/apps/agent/dist/table.js +13 -1
- package/apps/agent/dist/table.js.map +1 -1
- package/apps/consumer/dist/table.d.ts +12 -2
- package/apps/consumer/dist/table.js +13 -2
- package/apps/consumer/dist/table.js.map +1 -1
- package/apps/hub/dist/config.d.ts +1 -1
- package/apps/hub/dist/config.js +11 -0
- package/apps/hub/dist/config.js.map +1 -1
- package/apps/hub/dist/consumer.d.ts +4 -0
- package/apps/hub/dist/consumer.js +13 -1
- package/apps/hub/dist/consumer.js.map +1 -1
- package/apps/hub/dist/db.d.ts +4 -1
- package/apps/hub/dist/db.js +35 -7
- package/apps/hub/dist/db.js.map +1 -1
- package/apps/hub/dist/invites.js +9 -11
- package/apps/hub/dist/invites.js.map +1 -1
- package/apps/hub/dist/local.d.ts +8 -39
- package/apps/hub/dist/local.js +18 -191
- package/apps/hub/dist/local.js.map +1 -1
- package/apps/hub/dist/offerings.d.ts +7 -0
- package/apps/hub/dist/offerings.js +17 -0
- package/apps/hub/dist/offerings.js.map +1 -0
- package/apps/hub/dist/relay.d.ts +114 -0
- package/apps/hub/dist/relay.js +186 -0
- package/apps/hub/dist/relay.js.map +1 -0
- package/apps/hub/dist/table.d.ts +11 -1
- package/apps/hub/dist/table.js +13 -1
- package/apps/hub/dist/table.js.map +1 -1
- package/apps/hub/dist/tunnel.d.ts +9 -82
- package/apps/hub/dist/tunnel.js +43 -197
- package/apps/hub/dist/tunnel.js.map +1 -1
- package/package.json +1 -1
- package/packages/producer-core/dist/catalog.d.ts +23 -1
- package/packages/producer-core/dist/catalog.js +49 -15
- package/packages/producer-core/dist/catalog.js.map +1 -1
- package/packages/producer-core/dist/probe.d.ts +11 -0
- package/packages/producer-core/dist/probe.js +39 -0
- package/packages/producer-core/dist/probe.js.map +1 -1
- package/packages/protocol/dist/errors.d.ts +1 -0
- package/packages/protocol/dist/errors.js +1 -0
- package/packages/protocol/dist/errors.js.map +1 -1
- package/packages/protocol/dist/index.d.ts +1 -0
- package/packages/protocol/dist/index.js +1 -0
- package/packages/protocol/dist/index.js.map +1 -1
- package/packages/protocol/dist/messages.d.ts +5 -0
- package/packages/protocol/dist/messages.js.map +1 -1
- package/packages/protocol/dist/schedule.d.ts +83 -0
- package/packages/protocol/dist/schedule.js +421 -0
- package/packages/protocol/dist/schedule.js.map +1 -0
- package/packages/protocol/dist/time.js +5 -4
- package/packages/protocol/dist/time.js.map +1 -1
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Share-time scheduling: a producer may limit an offering to wall-clock
|
|
3
|
+
* windows in a named IANA time zone (allow-list, deny-list, or "every day").
|
|
4
|
+
*
|
|
5
|
+
* Design points, load-bearing for every function in this module:
|
|
6
|
+
* - All window/date semantics live on the *schedule timezone's* wall clock
|
|
7
|
+
* ("09:00-17:00" means 09:00 in the schedule tz, not anyone else's), so
|
|
8
|
+
* DST is handled naturally by Intl.DateTimeFormat: the wall time is
|
|
9
|
+
* decomposed per instant, never by arithmetic on UTC offsets.
|
|
10
|
+
* - `today`/`tomorrow` are config-side sugar: parseShareSchedule resolves
|
|
11
|
+
* them into concrete YYYY-MM-DD dates (against opts.now) before anything
|
|
12
|
+
* goes on the wire; validateShareSchedule deliberately rejects them.
|
|
13
|
+
* - Cross-midnight windows (start > end, e.g. 22:00-06:00) belong to their
|
|
14
|
+
* *start day*: the post-midnight tail (00:00-06:00) counts against the
|
|
15
|
+
* previous calendar day's day-matching, so a weekdays-only 22:00-06:00
|
|
16
|
+
* window stays open late Friday night / early Saturday morning but is
|
|
17
|
+
* closed from Saturday 22:00 on.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_TZ = 'Asia/Shanghai';
|
|
20
|
+
/** Every rendered time shows this zone (no DST); AWESHARE_TIMEZONE overrides. */
|
|
21
|
+
export function displayTimezone() {
|
|
22
|
+
return process.env.AWESHARE_TIMEZONE || DEFAULT_TZ;
|
|
23
|
+
}
|
|
24
|
+
const WINDOW_RE = /^([01]\d|2[0-3]):([0-5]\d)-([01]\d|2[0-3]):([0-5]\d)$/;
|
|
25
|
+
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
26
|
+
/** 'HH:MM-HH:MM' → [startMin, endMin] (0..1440); null when the shape is
|
|
27
|
+
* wrong or start==end (an empty window is a config error, not a no-op). */
|
|
28
|
+
function parseWindow(raw) {
|
|
29
|
+
const m = WINDOW_RE.exec(raw);
|
|
30
|
+
if (m === null)
|
|
31
|
+
return null;
|
|
32
|
+
const start = Number(m[1]) * 60 + Number(m[2]);
|
|
33
|
+
const end = Number(m[3]) * 60 + Number(m[4]);
|
|
34
|
+
if (start === end)
|
|
35
|
+
return null;
|
|
36
|
+
return [start, end];
|
|
37
|
+
}
|
|
38
|
+
/** 'YYYY-MM-DD' on the real calendar (2026-02-30 is not a date). */
|
|
39
|
+
function isRealDate(raw) {
|
|
40
|
+
if (!DATE_RE.test(raw))
|
|
41
|
+
return false;
|
|
42
|
+
const [y, m, d] = raw.split('-').map(Number);
|
|
43
|
+
if (y === undefined || m === undefined || d === undefined)
|
|
44
|
+
return false;
|
|
45
|
+
const probe = new Date(Date.UTC(y, m - 1, d));
|
|
46
|
+
return probe.getUTCFullYear() === y && probe.getUTCMonth() + 1 === m && probe.getUTCDate() === d;
|
|
47
|
+
}
|
|
48
|
+
/** Our wall-clock formatters are per-zone singletons (the 370-day scan calls
|
|
49
|
+
* them minute by minute); rebuilding per call would dominate that loop. */
|
|
50
|
+
const FORMATTERS = new Map();
|
|
51
|
+
function formatterFor(tz) {
|
|
52
|
+
let fmt = FORMATTERS.get(tz);
|
|
53
|
+
if (fmt === undefined) {
|
|
54
|
+
// hourCycle h23 gives '00'..'23', so midnight is 00, not 24.
|
|
55
|
+
fmt = new Intl.DateTimeFormat('en-US', {
|
|
56
|
+
timeZone: tz,
|
|
57
|
+
year: 'numeric',
|
|
58
|
+
month: '2-digit',
|
|
59
|
+
day: '2-digit',
|
|
60
|
+
hour: '2-digit',
|
|
61
|
+
minute: '2-digit',
|
|
62
|
+
hourCycle: 'h23',
|
|
63
|
+
});
|
|
64
|
+
FORMATTERS.set(tz, fmt);
|
|
65
|
+
}
|
|
66
|
+
return fmt;
|
|
67
|
+
}
|
|
68
|
+
/** Decompose an instant into the schedule timezone's wall-clock reading. */
|
|
69
|
+
function wallAt(tz, at) {
|
|
70
|
+
const parts = formatterFor(tz).formatToParts(at);
|
|
71
|
+
const out = {};
|
|
72
|
+
for (const part of parts)
|
|
73
|
+
out[part.type] = part.value;
|
|
74
|
+
const y = Number(out.year ?? 0);
|
|
75
|
+
const m = Number(out.month ?? 1);
|
|
76
|
+
const d = Number(out.day ?? 1);
|
|
77
|
+
const h = Number(out.hour ?? 0);
|
|
78
|
+
const min = Number(out.minute ?? 0);
|
|
79
|
+
const key = `${String(y).padStart(4, '0')}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
|
80
|
+
return { key, minutes: h * 60 + min };
|
|
81
|
+
}
|
|
82
|
+
/** Weekday for a wall 'YYYY-MM-DD' key. The date is read as pure UTC so the
|
|
83
|
+
* weekday is a property of the calendar date, independent of the zone (DST
|
|
84
|
+
* can shift hours, never which day of the week a date is). */
|
|
85
|
+
function weekdayOf(key) {
|
|
86
|
+
const [y, m, d] = key.split('-').map(Number);
|
|
87
|
+
return new Date(Date.UTC(y ?? 0, (m ?? 1) - 1, d ?? 1)).getUTCDay(); // 0=Sun..6=Sat
|
|
88
|
+
}
|
|
89
|
+
/** The calendar day `shift` days away from (y,m,d) *in tz* (shift -1 =
|
|
90
|
+
* yesterday, +1 = tomorrow). Probing the UTC noon of the target date and its
|
|
91
|
+
* neighbors is robust across every real IANA offset (-12..+14): a day's wall
|
|
92
|
+
* span always overlaps one of the three probes, and DST shifts (±1h) can
|
|
93
|
+
* never skip a calendar day. */
|
|
94
|
+
function shiftedDayKey(tz, key, shift) {
|
|
95
|
+
const [y, m, d] = key.split('-').map(Number);
|
|
96
|
+
const target = new Date(Date.UTC(y ?? 0, (m ?? 1) - 1, (d ?? 1) + shift));
|
|
97
|
+
const ty = target.getUTCFullYear();
|
|
98
|
+
const tm = target.getUTCMonth() + 1;
|
|
99
|
+
const td = target.getUTCDate();
|
|
100
|
+
const want = `${String(ty).padStart(4, '0')}-${String(tm).padStart(2, '0')}-${String(td).padStart(2, '0')}`;
|
|
101
|
+
for (const probeShift of [-1, 0, 1]) {
|
|
102
|
+
const probe = new Date(Date.UTC(ty, tm - 1, td + probeShift, 12));
|
|
103
|
+
if (wallAt(tz, probe).key === want)
|
|
104
|
+
return want;
|
|
105
|
+
}
|
|
106
|
+
return want;
|
|
107
|
+
}
|
|
108
|
+
/** Does this wall date match the day filter? */
|
|
109
|
+
const dayMatches = (days, key) => {
|
|
110
|
+
if (days === null)
|
|
111
|
+
return true;
|
|
112
|
+
if (days === 'weekdays') {
|
|
113
|
+
const wd = weekdayOf(key);
|
|
114
|
+
return wd >= 1 && wd <= 5;
|
|
115
|
+
}
|
|
116
|
+
if (days === 'weekend') {
|
|
117
|
+
const wd = weekdayOf(key);
|
|
118
|
+
return wd === 0 || wd === 6;
|
|
119
|
+
}
|
|
120
|
+
return days.includes(key);
|
|
121
|
+
};
|
|
122
|
+
/** A valid IANA name via the one API that can prove it. */
|
|
123
|
+
const isIanaTz = (tz) => {
|
|
124
|
+
try {
|
|
125
|
+
new Intl.DateTimeFormat('en-US', { timeZone: tz });
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
/** Validate a window *array*; shared by the config keys (shareWindows,
|
|
133
|
+
* blockWindows) and the wire fields (windows, exclude). Non-array → one
|
|
134
|
+
* problem; a bad item → an indexed problem carrying the raw value. */
|
|
135
|
+
function parseWindowList(value, key, problems) {
|
|
136
|
+
if (!Array.isArray(value)) {
|
|
137
|
+
problems.push(`${key} must be an array of HH:MM-HH:MM windows, got "${String(value)}"`);
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const out = [];
|
|
141
|
+
let ok = true;
|
|
142
|
+
value.forEach((item, i) => {
|
|
143
|
+
if (typeof item !== 'string' || parseWindow(item) === null) {
|
|
144
|
+
problems.push(`${key}[${i}] must be HH:MM-HH:MM (24h clock, start != end), got "${String(item)}"`);
|
|
145
|
+
ok = false;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
out.push(item);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return ok ? out : null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Config side: decode the [[offerings]] share-* keys. All four keys absent →
|
|
155
|
+
* no schedule at all (null); any present-but-invalid key fails the offering.
|
|
156
|
+
* The timezone (explicit shareTimezone, else opts.defaultTimezone, else
|
|
157
|
+
* displayTimezone) is resolved and frozen into the schedule here — never
|
|
158
|
+
* left as a problem — because 'today'/'tomorrow' must bake against the very
|
|
159
|
+
* zone the running requests will be gated on.
|
|
160
|
+
*/
|
|
161
|
+
export function parseShareSchedule(raw, opts) {
|
|
162
|
+
const hasWindows = raw.shareWindows !== undefined;
|
|
163
|
+
const hasBlock = raw.blockWindows !== undefined;
|
|
164
|
+
const hasDays = raw.shareDays !== undefined;
|
|
165
|
+
const hasTz = raw.shareTimezone !== undefined;
|
|
166
|
+
if (!hasWindows && !hasBlock && !hasDays && !hasTz) {
|
|
167
|
+
return { schedule: null, problems: [] };
|
|
168
|
+
}
|
|
169
|
+
const problems = [];
|
|
170
|
+
if (hasWindows && hasBlock) {
|
|
171
|
+
problems.push('shareWindows and blockWindows are mutually exclusive — pick an allowlist or a denylist');
|
|
172
|
+
}
|
|
173
|
+
// Running timezone first: 'today'/'tomorrow' resolution below needs it,
|
|
174
|
+
// and a bad explicit shareTimezone fails the offering regardless.
|
|
175
|
+
let tz = '';
|
|
176
|
+
if (hasTz) {
|
|
177
|
+
if (typeof raw.shareTimezone === 'string' && isIanaTz(raw.shareTimezone))
|
|
178
|
+
tz = raw.shareTimezone;
|
|
179
|
+
else
|
|
180
|
+
problems.push(`shareTimezone must be a valid IANA time zone, got "${String(raw.shareTimezone)}"`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
tz = opts?.defaultTimezone ?? displayTimezone();
|
|
184
|
+
if (!isIanaTz(tz))
|
|
185
|
+
problems.push(`shareTimezone must be a valid IANA time zone, got "${tz}"`);
|
|
186
|
+
}
|
|
187
|
+
// Allows and blocks are one-or-the-other; when both keys appear the
|
|
188
|
+
// mutual-exclusion problem already covers why, so validate neither list.
|
|
189
|
+
let windows = null;
|
|
190
|
+
let exclude = null;
|
|
191
|
+
if (hasWindows && !hasBlock) {
|
|
192
|
+
const list = parseWindowList(raw.shareWindows, 'shareWindows', problems);
|
|
193
|
+
if (list !== null)
|
|
194
|
+
windows = list;
|
|
195
|
+
}
|
|
196
|
+
else if (hasBlock && !hasWindows) {
|
|
197
|
+
const list = parseWindowList(raw.blockWindows, 'blockWindows', problems);
|
|
198
|
+
if (list !== null)
|
|
199
|
+
exclude = list;
|
|
200
|
+
}
|
|
201
|
+
let days = null;
|
|
202
|
+
if (hasDays) {
|
|
203
|
+
const rawDays = raw.shareDays;
|
|
204
|
+
if (typeof rawDays === 'string') {
|
|
205
|
+
if (rawDays === 'everyday' || rawDays === 'weekdays' || rawDays === 'weekend') {
|
|
206
|
+
days = rawDays === 'everyday' ? null : rawDays;
|
|
207
|
+
}
|
|
208
|
+
else if (rawDays === 'today' || rawDays === 'tomorrow') {
|
|
209
|
+
if (tz !== '') {
|
|
210
|
+
const now = opts?.now ?? new Date();
|
|
211
|
+
const todayKey = wallAt(tz, now).key;
|
|
212
|
+
days = rawDays === 'today' ? [todayKey] : [shiftedDayKey(tz, todayKey, 1)];
|
|
213
|
+
}
|
|
214
|
+
// tz === '' means the timezone problem above already fails this block.
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
problems.push(`shareDays must be everyday, weekdays, weekend, today, tomorrow or an array of YYYY-MM-DD dates, got "${rawDays}"`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else if (Array.isArray(rawDays)) {
|
|
221
|
+
if (rawDays.length === 0) {
|
|
222
|
+
problems.push('shareDays must be a non-empty array of YYYY-MM-DD dates');
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const list = [];
|
|
226
|
+
let ok = true;
|
|
227
|
+
rawDays.forEach((item, i) => {
|
|
228
|
+
if (typeof item !== 'string' || !isRealDate(item)) {
|
|
229
|
+
problems.push(`shareDays[${i}] must be YYYY-MM-DD, got "${String(item)}"`);
|
|
230
|
+
ok = false;
|
|
231
|
+
}
|
|
232
|
+
else {
|
|
233
|
+
list.push(item);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
if (ok)
|
|
237
|
+
days = list;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
problems.push(`shareDays must be a non-empty array of YYYY-MM-DD dates, got "${String(rawDays)}"`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (problems.length > 0)
|
|
245
|
+
return { schedule: null, problems: [...problems] };
|
|
246
|
+
return { schedule: { timezone: tz, days, windows, exclude }, problems: [] };
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Wire side (hub): validate the *already resolved* shape a producer sent, so
|
|
250
|
+
* the hub only ever evaluates normalized schedules. The config-only words
|
|
251
|
+
* (today/tomorrow/everyday) and every malformed value land as a problem —
|
|
252
|
+
* 'today' is rejected here, exactly as the config side consumes it.
|
|
253
|
+
*/
|
|
254
|
+
export function validateShareSchedule(value) {
|
|
255
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
256
|
+
return { schedule: null, problems: ['schedule must be an object'] };
|
|
257
|
+
}
|
|
258
|
+
const v = value;
|
|
259
|
+
const problems = [];
|
|
260
|
+
let timezone = '';
|
|
261
|
+
if (typeof v.timezone !== 'string' || !isIanaTz(v.timezone)) {
|
|
262
|
+
problems.push(`timezone must be a valid IANA time zone, got "${String(v.timezone)}"`);
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
timezone = v.timezone;
|
|
266
|
+
}
|
|
267
|
+
let days = null;
|
|
268
|
+
const rawDays = v.days;
|
|
269
|
+
if (rawDays === undefined) {
|
|
270
|
+
problems.push('days must be present (null, "weekdays", "weekend" or an array of YYYY-MM-DD dates)');
|
|
271
|
+
}
|
|
272
|
+
else if (rawDays === null) {
|
|
273
|
+
days = null;
|
|
274
|
+
}
|
|
275
|
+
else if (rawDays === 'weekdays' || rawDays === 'weekend') {
|
|
276
|
+
days = rawDays;
|
|
277
|
+
}
|
|
278
|
+
else if (Array.isArray(rawDays)) {
|
|
279
|
+
if (rawDays.length === 0) {
|
|
280
|
+
problems.push('days must not be an empty array');
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
const list = [];
|
|
284
|
+
let ok = true;
|
|
285
|
+
rawDays.forEach((item, i) => {
|
|
286
|
+
if (typeof item !== 'string' || !isRealDate(item)) {
|
|
287
|
+
problems.push(`days[${i}] must be YYYY-MM-DD, got "${String(item)}"`);
|
|
288
|
+
ok = false;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
list.push(item);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
if (ok)
|
|
295
|
+
days = list;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
problems.push(`days must be null, "weekdays", "weekend" or an array of YYYY-MM-DD dates, got "${String(rawDays)}"`);
|
|
300
|
+
}
|
|
301
|
+
const rawWindows = v.windows;
|
|
302
|
+
const rawExclude = v.exclude;
|
|
303
|
+
let windows = null;
|
|
304
|
+
let exclude = null;
|
|
305
|
+
if (rawWindows === undefined) {
|
|
306
|
+
problems.push('windows is required (null or an array of HH:MM-HH:MM windows)');
|
|
307
|
+
}
|
|
308
|
+
else if (rawWindows !== null) {
|
|
309
|
+
const list = parseWindowList(rawWindows, 'windows', problems);
|
|
310
|
+
if (list !== null)
|
|
311
|
+
windows = list;
|
|
312
|
+
}
|
|
313
|
+
if (rawExclude === undefined) {
|
|
314
|
+
problems.push('exclude is required (null or an array of HH:MM-HH:MM windows)');
|
|
315
|
+
}
|
|
316
|
+
else if (rawExclude !== null) {
|
|
317
|
+
const list = parseWindowList(rawExclude, 'exclude', problems);
|
|
318
|
+
if (list !== null)
|
|
319
|
+
exclude = list;
|
|
320
|
+
}
|
|
321
|
+
if (windows !== null && exclude !== null) {
|
|
322
|
+
problems.push('windows and exclude are mutually exclusive — pick an allowlist or a denylist');
|
|
323
|
+
}
|
|
324
|
+
if (problems.length > 0)
|
|
325
|
+
return { schedule: null, problems };
|
|
326
|
+
return {
|
|
327
|
+
schedule: { timezone, days: days ?? null, windows: windows ?? null, exclude: exclude ?? null },
|
|
328
|
+
problems: [],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Evaluate a schedule at an instant. The day filter is applied per window's
|
|
333
|
+
* start day: a single-day window exists only on matching wall days; the tail
|
|
334
|
+
* of a crossing window needs the PREVIOUS day's match (weekdays 22:00-06:00
|
|
335
|
+
* stays open Friday night, but Saturday's 22:00 is closed because Saturday
|
|
336
|
+
* itself does not match). Deny-list windows are day-agnostic — they block
|
|
337
|
+
* that wall time no matter what day it is.
|
|
338
|
+
*/
|
|
339
|
+
export function isShareOpen(schedule, at) {
|
|
340
|
+
const now = wallAt(schedule.timezone, at);
|
|
341
|
+
if (schedule.windows !== null) {
|
|
342
|
+
const open = schedule.windows.some((w) => {
|
|
343
|
+
const win = parseWindow(w);
|
|
344
|
+
if (win === null)
|
|
345
|
+
return false; // wire-shape error; the validator catches it
|
|
346
|
+
const [s, e] = win;
|
|
347
|
+
if (s < e) {
|
|
348
|
+
return s <= now.minutes && now.minutes < e && dayMatches(schedule.days, now.key);
|
|
349
|
+
}
|
|
350
|
+
// crossed midnight: T>=s started today, T<e is yesterday's tail
|
|
351
|
+
return ((now.minutes >= s && dayMatches(schedule.days, now.key)) ||
|
|
352
|
+
(now.minutes < e &&
|
|
353
|
+
dayMatches(schedule.days, shiftedDayKey(schedule.timezone, now.key, -1))));
|
|
354
|
+
});
|
|
355
|
+
if (!open)
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
else if (!dayMatches(schedule.days, now.key)) {
|
|
359
|
+
// all-day schedule: the gate is just whether today matches
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
if (schedule.exclude !== null) {
|
|
363
|
+
const blocked = schedule.exclude.some((w) => {
|
|
364
|
+
const win = parseWindow(w);
|
|
365
|
+
if (win === null)
|
|
366
|
+
return false;
|
|
367
|
+
const [s, e] = win;
|
|
368
|
+
return s < e ? s <= now.minutes && now.minutes < e : now.minutes >= s || now.minutes < e;
|
|
369
|
+
});
|
|
370
|
+
if (blocked)
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The next minute (from `from`'s minute + 1) at which the schedule opens, or
|
|
377
|
+
* null when nothing opens within the next 370 days. The scan is a plain
|
|
378
|
+
* 1-minute walk so DST transitions and crossing windows need no special
|
|
379
|
+
* casing; a date-list pre-filter short-circuits the common hopeless cases
|
|
380
|
+
* (concrete dates already past or beyond the horizon) — which is exactly
|
|
381
|
+
* what an exhaustive walk would answer, only instantly.
|
|
382
|
+
*/
|
|
383
|
+
export function nextShareOpen(schedule, from) {
|
|
384
|
+
if (Array.isArray(schedule.days)) {
|
|
385
|
+
const today = wallAt(schedule.timezone, from).key;
|
|
386
|
+
// +1 day buffer: IANA offsets make the wall-date key of from+370d shift
|
|
387
|
+
// by up to a day, and the walk below may still prove 370 exactness.
|
|
388
|
+
const horizon = wallAt(schedule.timezone, new Date(from.getTime() + 371 * 86_400_000)).key;
|
|
389
|
+
if (!schedule.days.some((d) => d >= today && d <= horizon))
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
const start = Math.floor(from.getTime() / 60_000) * 60_000 + 60_000;
|
|
393
|
+
const cap = 370 * 24 * 60; // minutes
|
|
394
|
+
for (let i = 0; i < cap; i++) {
|
|
395
|
+
const at = new Date(start + i * 60_000);
|
|
396
|
+
if (isShareOpen(schedule, at))
|
|
397
|
+
return at;
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
/** Human rendering: '{days} {windows}', e.g. 'daily 00:00-06:00' or
|
|
402
|
+
* 'weekdays !14:00-18:00'; the tz is appended only when it differs from the
|
|
403
|
+
* viewer's, as '@Asia/Shanghai'. '-' for absent schedules. */
|
|
404
|
+
export function formatShareSchedule(schedule, viewerTz = displayTimezone()) {
|
|
405
|
+
if (schedule === null || schedule === undefined)
|
|
406
|
+
return '-';
|
|
407
|
+
const dayPrefix = schedule.days === null
|
|
408
|
+
? 'daily'
|
|
409
|
+
: schedule.days === 'weekdays' || schedule.days === 'weekend'
|
|
410
|
+
? schedule.days
|
|
411
|
+
: schedule.days.join(',');
|
|
412
|
+
const windowText = schedule.windows === null && schedule.exclude === null
|
|
413
|
+
? 'all day'
|
|
414
|
+
: [
|
|
415
|
+
...(schedule.windows ?? []).map((w) => w),
|
|
416
|
+
...(schedule.exclude ?? []).map((w) => `!${w}`),
|
|
417
|
+
].join('; ');
|
|
418
|
+
const text = `${dayPrefix} ${windowText}`;
|
|
419
|
+
return schedule.timezone !== viewerTz ? `${text}@${schedule.timezone}` : text;
|
|
420
|
+
}
|
|
421
|
+
//# sourceMappingURL=schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule.js","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { displayTimezone } from './schedule.js';
|
|
1
2
|
// Wall-clock display times for every CLI table and log line. The wire, the
|
|
2
3
|
// SQLite rows and `--json` stay UTC ISO — only what a human reads is converted.
|
|
3
|
-
/** Every rendered time shows this zone (no DST); AWESHARE_TIMEZONE overrides. */
|
|
4
|
-
const DEFAULT_TZ = 'Asia/Shanghai';
|
|
5
4
|
let cachedTz = null;
|
|
6
5
|
let cachedFmt = null;
|
|
7
6
|
/** One formatter for the active zone, rebuilt only when the env var changes —
|
|
8
|
-
* an invalid IANA name fails with a clear message instead of per-row noise.
|
|
7
|
+
* an invalid IANA name fails with a clear message instead of per-row noise.
|
|
8
|
+
* The default-zone rule lives in schedule.ts so share schedules and rendered
|
|
9
|
+
* times always agree on what "now" means. */
|
|
9
10
|
function formatter() {
|
|
10
|
-
const tz =
|
|
11
|
+
const tz = displayTimezone();
|
|
11
12
|
if (tz !== cachedTz || cachedFmt === null) {
|
|
12
13
|
try {
|
|
13
14
|
cachedFmt = new Intl.DateTimeFormat('en-CA', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"time.js","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"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"}
|