@ai-matrx/records 0.72.23 → 0.73.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/CHANGELOG.md +10 -0
- package/dist/list/index.cjs +221 -0
- package/dist/list/index.cjs.map +1 -0
- package/dist/list/index.d.cts +395 -0
- package/dist/list/index.d.ts +395 -0
- package/dist/list/index.js +198 -0
- package/dist/list/index.js.map +1 -0
- package/dist/memory/index.cjs +235 -4
- package/dist/memory/index.cjs.map +1 -1
- package/dist/memory/index.js +235 -4
- package/dist/memory/index.js.map +1 -1
- package/package.json +12 -1
package/dist/memory/index.js
CHANGED
|
@@ -2393,6 +2393,146 @@ function matching(world, table, args) {
|
|
|
2393
2393
|
if (search) ids = ids.filter((id) => JSON.stringify(readDocument(world, table, id)).toLowerCase().includes(search));
|
|
2394
2394
|
return sortRows(world, table, ids, args["p_sort"]);
|
|
2395
2395
|
}
|
|
2396
|
+
var DAY_MS = 864e5;
|
|
2397
|
+
function bucketOf(value, by) {
|
|
2398
|
+
if (typeof value !== "string" || value.length < 10) return null;
|
|
2399
|
+
const [y, m, d] = value.slice(0, 10).split("-").map(Number);
|
|
2400
|
+
let at = new Date(Date.UTC(y, m - 1, d));
|
|
2401
|
+
if (by === "week") at = new Date(at.getTime() - (at.getUTCDay() + 6) % 7 * DAY_MS);
|
|
2402
|
+
else if (by === "month") at = new Date(Date.UTC(y, m - 1, 1));
|
|
2403
|
+
else if (by === "quarter") at = new Date(Date.UTC(y, Math.floor((m - 1) / 3) * 3, 1));
|
|
2404
|
+
else if (by === "year") at = new Date(Date.UTC(y, 0, 1));
|
|
2405
|
+
return `${at.toISOString().slice(0, 10)}T00:00:00+00:00`;
|
|
2406
|
+
}
|
|
2407
|
+
function groupValues(doc, stored, key) {
|
|
2408
|
+
const shown = doc[key];
|
|
2409
|
+
const raw = stored[key];
|
|
2410
|
+
const pick = typeof raw === "string" && raw === shown ? raw : shown ?? raw;
|
|
2411
|
+
const list = Array.isArray(pick) ? pick : [pick];
|
|
2412
|
+
const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
|
|
2413
|
+
return out.length ? out : [null];
|
|
2414
|
+
}
|
|
2415
|
+
function runBlock(world, subject, raw, canvas, index) {
|
|
2416
|
+
const table = world.tableById.get(String(raw["table_id"] ?? subject));
|
|
2417
|
+
const title = String(raw["title"] ?? `Block ${index + 1}`);
|
|
2418
|
+
const base = { ...raw, title, table_id: table?.id ?? subject, ms: 0 };
|
|
2419
|
+
if (!table) return { ...base, rows: [], refused: "This block's table is not in this template." };
|
|
2420
|
+
if (raw["kind"] === "stuck") return { ...base, rows: [] };
|
|
2421
|
+
const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
|
|
2422
|
+
const groupBy = (raw["group_by"] ?? []).slice();
|
|
2423
|
+
const bucket = raw["bucket"] ?? null;
|
|
2424
|
+
const ids = table.order.filter((id) => admits(world, table, id, raw["filter"]) && admits(world, table, id, canvas));
|
|
2425
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2426
|
+
for (const id of ids) {
|
|
2427
|
+
const doc = readDocument(world, table, id);
|
|
2428
|
+
const stored = table.rows.get(id) ?? {};
|
|
2429
|
+
let combos = [{}];
|
|
2430
|
+
for (const key of groupBy) {
|
|
2431
|
+
const values = groupValues(doc, stored, key);
|
|
2432
|
+
combos = combos.flatMap((c) => values.map((v) => ({ ...c, [key]: v })));
|
|
2433
|
+
}
|
|
2434
|
+
if (bucket?.key) {
|
|
2435
|
+
const at = bucketOf(doc[bucket.key] ?? stored[bucket.key], bucket.by ?? "month");
|
|
2436
|
+
if (at === null) continue;
|
|
2437
|
+
combos = combos.map((c) => ({ ...c, [`${bucket.key}_${bucket.by ?? "month"}`]: at }));
|
|
2438
|
+
}
|
|
2439
|
+
for (const c of combos) {
|
|
2440
|
+
const k = JSON.stringify(c);
|
|
2441
|
+
const g = groups.get(k) ?? { groups: c, ids: [] };
|
|
2442
|
+
g.ids.push(id);
|
|
2443
|
+
groups.set(k, g);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
if (!groupBy.length && !bucket?.key && !groups.size) groups.set("{}", { groups: {}, ids: [] });
|
|
2447
|
+
const measureName = (m) => m.op === "count" ? "count" : `${m.op}_${m.key ?? ""}`;
|
|
2448
|
+
let rows = [...groups.values()].map((g) => {
|
|
2449
|
+
const out = {};
|
|
2450
|
+
for (const m of measures) {
|
|
2451
|
+
if (m.op === "count") {
|
|
2452
|
+
out["count"] = g.ids.length;
|
|
2453
|
+
continue;
|
|
2454
|
+
}
|
|
2455
|
+
const nums = g.ids.map((id) => readDocument(world, table, id)[m.key ?? ""]).filter((v) => typeof v === "number");
|
|
2456
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
2457
|
+
out[measureName(m)] = m.op === "sum" ? sum : !nums.length ? null : m.op === "avg" ? sum / nums.length : m.op === "min" ? Math.min(...nums) : m.op === "max" ? Math.max(...nums) : null;
|
|
2458
|
+
}
|
|
2459
|
+
return { groups: g.groups, measures: out, row_count: g.ids.length };
|
|
2460
|
+
});
|
|
2461
|
+
const primary = measures[0] ? measureName(measures[0]) : "count";
|
|
2462
|
+
if (bucket?.key) {
|
|
2463
|
+
const k = `${bucket.key}_${bucket.by ?? "month"}`;
|
|
2464
|
+
rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
|
|
2465
|
+
} else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
|
|
2466
|
+
const limit = Number(raw["limit"] ?? 0);
|
|
2467
|
+
if (limit > 0) rows = rows.slice(0, limit);
|
|
2468
|
+
return { ...base, measures, group_by: groupBy, rows };
|
|
2469
|
+
}
|
|
2470
|
+
function bookingAvailability(world, raw) {
|
|
2471
|
+
const num = (k, fallback) => typeof raw[k] === "number" ? raw[k] : fallback;
|
|
2472
|
+
return {
|
|
2473
|
+
timezone: String(raw["timezone"] ?? world.timezone),
|
|
2474
|
+
slot_minutes: num("slot_minutes", 30),
|
|
2475
|
+
buffer_minutes: num("buffer_minutes", 0),
|
|
2476
|
+
lead_minutes: num("lead_minutes", 0),
|
|
2477
|
+
max_per_day: num("max_per_day", 0),
|
|
2478
|
+
days: num("days", 14),
|
|
2479
|
+
windows: (raw["windows"] ?? []).map((w) => ({
|
|
2480
|
+
weekday: Number(w["weekday"] ?? 1),
|
|
2481
|
+
from: String(w["from"] ?? "09:00"),
|
|
2482
|
+
to: String(w["to"] ?? "17:00"),
|
|
2483
|
+
member_user_id: null
|
|
2484
|
+
}))
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
function zoneOffset2(zone, at) {
|
|
2488
|
+
const parts = new Intl.DateTimeFormat("en-US", { timeZone: zone, hourCycle: "h23", year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit" }).formatToParts(new Date(at)).reduce((acc, p) => p.type === "literal" ? acc : { ...acc, [p.type]: Number(p.value) }, {});
|
|
2489
|
+
return (Date.UTC(parts["year"], parts["month"] - 1, parts["day"], parts["hour"], parts["minute"]) - at) / 6e4;
|
|
2490
|
+
}
|
|
2491
|
+
function zonedInstant(zone, day, minutes) {
|
|
2492
|
+
const guess = day + minutes * 6e4;
|
|
2493
|
+
return guess - zoneOffset2(zone, guess - zoneOffset2(zone, guess) * 6e4) * 6e4;
|
|
2494
|
+
}
|
|
2495
|
+
function bookingSlots(world, table, a, days) {
|
|
2496
|
+
const zone = (() => {
|
|
2497
|
+
try {
|
|
2498
|
+
new Intl.DateTimeFormat("en-US", { timeZone: a.timezone });
|
|
2499
|
+
return a.timezone;
|
|
2500
|
+
} catch {
|
|
2501
|
+
return "UTC";
|
|
2502
|
+
}
|
|
2503
|
+
})();
|
|
2504
|
+
const taken = /* @__PURE__ */ new Set();
|
|
2505
|
+
for (const id of table.order) {
|
|
2506
|
+
for (const v of Object.values(table.rows.get(id) ?? {})) {
|
|
2507
|
+
if (typeof v === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(v)) taken.add(new Date(v).getTime());
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
const toMin = (hhmm) => {
|
|
2511
|
+
const [h, m2] = hhmm.split(":").map(Number);
|
|
2512
|
+
return (h ?? 0) * 60 + (m2 ?? 0);
|
|
2513
|
+
};
|
|
2514
|
+
const [y, m, d] = world.today.split("-").map(Number);
|
|
2515
|
+
const start = Date.UTC(y, m - 1, d);
|
|
2516
|
+
const earliest = zonedInstant(zone, start, 9 * 60) + a.lead_minutes * 6e4;
|
|
2517
|
+
const step = Math.max(5, a.slot_minutes + a.buffer_minutes);
|
|
2518
|
+
const slots = [];
|
|
2519
|
+
for (let i = 0; i < Math.max(1, days); i += 1) {
|
|
2520
|
+
const day = start + i * DAY_MS;
|
|
2521
|
+
const weekday = new Date(day).getUTCDay();
|
|
2522
|
+
let today = 0;
|
|
2523
|
+
for (const w of a.windows.filter((x) => x.weekday === weekday)) {
|
|
2524
|
+
for (let t = toMin(w.from); t + a.slot_minutes <= toMin(w.to); t += step) {
|
|
2525
|
+
if (a.max_per_day > 0 && today >= a.max_per_day) break;
|
|
2526
|
+
const at = zonedInstant(zone, day, t);
|
|
2527
|
+
if (at < earliest) continue;
|
|
2528
|
+
today += 1;
|
|
2529
|
+
const iso = new Date(at).toISOString();
|
|
2530
|
+
slots.push({ key: iso, at: iso, taken: taken.has(at), member_user_id: null });
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
return slots;
|
|
2535
|
+
}
|
|
2396
2536
|
var VIEWER = "viewer";
|
|
2397
2537
|
function memoryDataSource(world) {
|
|
2398
2538
|
const looks = /* @__PURE__ */ new Map();
|
|
@@ -2601,15 +2741,106 @@ function memoryDataSource(world) {
|
|
|
2601
2741
|
record_stage_pending: () => ok([]),
|
|
2602
2742
|
io_imports: () => ok([]),
|
|
2603
2743
|
relation_words: (args) => ok(nameOf(String(args["p_value"] ?? ""))),
|
|
2744
|
+
// The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
|
|
2604
2745
|
forms: (args) => ok(
|
|
2605
|
-
world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2746
|
+
world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2747
|
+
form_id: f.form_id,
|
|
2748
|
+
table_id: f.table_id,
|
|
2749
|
+
title: f.title,
|
|
2750
|
+
slug: f.token,
|
|
2751
|
+
published_at: `${world.today}T09:00:00Z`,
|
|
2752
|
+
closed_at: null,
|
|
2753
|
+
submission_cap: null,
|
|
2754
|
+
responses: 0,
|
|
2755
|
+
in_table: 0,
|
|
2756
|
+
held: 0,
|
|
2757
|
+
rejected: 0,
|
|
2758
|
+
state: "open",
|
|
2759
|
+
quarantine_rule_id: null,
|
|
2760
|
+
notify_rule_id: null,
|
|
2761
|
+
questions: f.questions,
|
|
2762
|
+
presentation: { ...f.presentation, questions: f.presentation["questions"] ?? f.questions }
|
|
2763
|
+
}))
|
|
2606
2764
|
),
|
|
2765
|
+
form_preview_asks: (args) => {
|
|
2766
|
+
const t = tableOf(args);
|
|
2767
|
+
const values = args["p_values"] ?? {};
|
|
2768
|
+
return ok(
|
|
2769
|
+
(args["p_questions"] ?? []).map((q) => {
|
|
2770
|
+
const when = q["show_if"] ?? q["showIf"] ?? null;
|
|
2771
|
+
const asked = !when || !t ? true : rule(t, values, values, when) !== false;
|
|
2772
|
+
return { field_key: String(q["field"] ?? q["key"] ?? ""), asked, decided: true, said: null };
|
|
2773
|
+
})
|
|
2774
|
+
);
|
|
2775
|
+
},
|
|
2607
2776
|
bookings: (args) => ok(
|
|
2608
|
-
world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2777
|
+
world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
|
|
2778
|
+
form_id: f.form_id,
|
|
2779
|
+
table_id: f.table_id,
|
|
2780
|
+
title: f.title,
|
|
2781
|
+
slug: f.token,
|
|
2782
|
+
published_at: `${world.today}T09:00:00Z`,
|
|
2783
|
+
closed_at: null,
|
|
2784
|
+
slot_minutes: Number(f.booking["slot_minutes"] ?? 30),
|
|
2785
|
+
timezone: String(f.booking["timezone"] ?? world.timezone),
|
|
2786
|
+
slot_table_id: null,
|
|
2787
|
+
booked: 0,
|
|
2788
|
+
cancelled: 0,
|
|
2789
|
+
upcoming: 0,
|
|
2790
|
+
held: 0,
|
|
2791
|
+
next_at: null,
|
|
2792
|
+
state: "open"
|
|
2793
|
+
}))
|
|
2609
2794
|
),
|
|
2795
|
+
booking_public: (args) => {
|
|
2796
|
+
const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
|
|
2797
|
+
const t = f ? world.tableById.get(f.table_id) : void 0;
|
|
2798
|
+
if (!f || !t) return refuse("That booking page is not in this template.", "P0002");
|
|
2799
|
+
const availability = bookingAvailability(world, f.booking);
|
|
2800
|
+
return ok({
|
|
2801
|
+
form_id: f.form_id,
|
|
2802
|
+
organization_id: world.organization_id,
|
|
2803
|
+
table_id: t.id,
|
|
2804
|
+
title: f.title,
|
|
2805
|
+
presentation: { ...f.presentation, questions: f.questions },
|
|
2806
|
+
fields: t.fields.map((x) => ({ id: x.id, ...x.data })),
|
|
2807
|
+
honeypot_key: null,
|
|
2808
|
+
availability,
|
|
2809
|
+
slots: bookingSlots(world, t, availability, Number(args["p_days"] ?? availability.days)),
|
|
2810
|
+
state: "open",
|
|
2811
|
+
message: null
|
|
2812
|
+
});
|
|
2813
|
+
},
|
|
2610
2814
|
dashboards: (args) => ok(
|
|
2611
|
-
world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
|
|
2612
|
-
|
|
2815
|
+
world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
|
|
2816
|
+
dashboard_id: d.dashboard_id,
|
|
2817
|
+
table_id: d.table_id,
|
|
2818
|
+
name: d.name,
|
|
2819
|
+
blocks: d.blocks,
|
|
2820
|
+
presentation: {},
|
|
2821
|
+
block_count: d.blocks.length,
|
|
2822
|
+
version: 1,
|
|
2823
|
+
created_at: `${world.today}T09:00:00Z`,
|
|
2824
|
+
updated_at: `${world.today}T09:00:00Z`
|
|
2825
|
+
}))
|
|
2826
|
+
),
|
|
2827
|
+
dashboard_run: (args) => {
|
|
2828
|
+
const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
|
|
2829
|
+
if (!d) return refuse("That dashboard is not in this template.", "P0002");
|
|
2830
|
+
const canvas = args["p_filter"] ?? {};
|
|
2831
|
+
return ok({
|
|
2832
|
+
dashboard_id: d.dashboard_id,
|
|
2833
|
+
name: d.name,
|
|
2834
|
+
subject_table_id: d.table_id,
|
|
2835
|
+
presentation: {},
|
|
2836
|
+
filter: canvas,
|
|
2837
|
+
grain: null,
|
|
2838
|
+
compare: null,
|
|
2839
|
+
calendar: { time_zone: world.timezone, week_start: "monday" },
|
|
2840
|
+
blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
|
|
2841
|
+
});
|
|
2842
|
+
},
|
|
2843
|
+
dashboard_stuck: () => ok([])
|
|
2613
2844
|
};
|
|
2614
2845
|
const source = {
|
|
2615
2846
|
world,
|