@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.
@@ -2424,6 +2424,146 @@ function matching(world, table, args) {
2424
2424
  if (search) ids = ids.filter((id) => JSON.stringify(readDocument(world, table, id)).toLowerCase().includes(search));
2425
2425
  return sortRows(world, table, ids, args["p_sort"]);
2426
2426
  }
2427
+ var DAY_MS = 864e5;
2428
+ function bucketOf(value, by) {
2429
+ if (typeof value !== "string" || value.length < 10) return null;
2430
+ const [y, m, d] = value.slice(0, 10).split("-").map(Number);
2431
+ let at = new Date(Date.UTC(y, m - 1, d));
2432
+ if (by === "week") at = new Date(at.getTime() - (at.getUTCDay() + 6) % 7 * DAY_MS);
2433
+ else if (by === "month") at = new Date(Date.UTC(y, m - 1, 1));
2434
+ else if (by === "quarter") at = new Date(Date.UTC(y, Math.floor((m - 1) / 3) * 3, 1));
2435
+ else if (by === "year") at = new Date(Date.UTC(y, 0, 1));
2436
+ return `${at.toISOString().slice(0, 10)}T00:00:00+00:00`;
2437
+ }
2438
+ function groupValues(doc, stored, key) {
2439
+ const shown = doc[key];
2440
+ const raw = stored[key];
2441
+ const pick = typeof raw === "string" && raw === shown ? raw : shown ?? raw;
2442
+ const list = Array.isArray(pick) ? pick : [pick];
2443
+ const out = list.map((v) => v === void 0 || v === null || v === "" ? null : String(v));
2444
+ return out.length ? out : [null];
2445
+ }
2446
+ function runBlock(world, subject, raw, canvas, index) {
2447
+ const table = world.tableById.get(String(raw["table_id"] ?? subject));
2448
+ const title = String(raw["title"] ?? `Block ${index + 1}`);
2449
+ const base = { ...raw, title, table_id: table?.id ?? subject, ms: 0 };
2450
+ if (!table) return { ...base, rows: [], refused: "This block's table is not in this template." };
2451
+ if (raw["kind"] === "stuck") return { ...base, rows: [] };
2452
+ const measures = (raw["measures"] ?? [{ op: "count" }]).map((m) => ({ op: String(m["op"] ?? "count"), key: m["key"] }));
2453
+ const groupBy = (raw["group_by"] ?? []).slice();
2454
+ const bucket = raw["bucket"] ?? null;
2455
+ const ids = table.order.filter((id) => admits(world, table, id, raw["filter"]) && admits(world, table, id, canvas));
2456
+ const groups = /* @__PURE__ */ new Map();
2457
+ for (const id of ids) {
2458
+ const doc = readDocument(world, table, id);
2459
+ const stored = table.rows.get(id) ?? {};
2460
+ let combos = [{}];
2461
+ for (const key of groupBy) {
2462
+ const values = groupValues(doc, stored, key);
2463
+ combos = combos.flatMap((c) => values.map((v) => ({ ...c, [key]: v })));
2464
+ }
2465
+ if (bucket?.key) {
2466
+ const at = bucketOf(doc[bucket.key] ?? stored[bucket.key], bucket.by ?? "month");
2467
+ if (at === null) continue;
2468
+ combos = combos.map((c) => ({ ...c, [`${bucket.key}_${bucket.by ?? "month"}`]: at }));
2469
+ }
2470
+ for (const c of combos) {
2471
+ const k = JSON.stringify(c);
2472
+ const g = groups.get(k) ?? { groups: c, ids: [] };
2473
+ g.ids.push(id);
2474
+ groups.set(k, g);
2475
+ }
2476
+ }
2477
+ if (!groupBy.length && !bucket?.key && !groups.size) groups.set("{}", { groups: {}, ids: [] });
2478
+ const measureName = (m) => m.op === "count" ? "count" : `${m.op}_${m.key ?? ""}`;
2479
+ let rows = [...groups.values()].map((g) => {
2480
+ const out = {};
2481
+ for (const m of measures) {
2482
+ if (m.op === "count") {
2483
+ out["count"] = g.ids.length;
2484
+ continue;
2485
+ }
2486
+ const nums = g.ids.map((id) => readDocument(world, table, id)[m.key ?? ""]).filter((v) => typeof v === "number");
2487
+ const sum = nums.reduce((a, b) => a + b, 0);
2488
+ 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;
2489
+ }
2490
+ return { groups: g.groups, measures: out, row_count: g.ids.length };
2491
+ });
2492
+ const primary = measures[0] ? measureName(measures[0]) : "count";
2493
+ if (bucket?.key) {
2494
+ const k = `${bucket.key}_${bucket.by ?? "month"}`;
2495
+ rows.sort((a, b) => String(a.groups[k]).localeCompare(String(b.groups[k])));
2496
+ } else rows.sort((a, b) => (b.measures[primary] ?? 0) - (a.measures[primary] ?? 0));
2497
+ const limit = Number(raw["limit"] ?? 0);
2498
+ if (limit > 0) rows = rows.slice(0, limit);
2499
+ return { ...base, measures, group_by: groupBy, rows };
2500
+ }
2501
+ function bookingAvailability(world, raw) {
2502
+ const num = (k, fallback) => typeof raw[k] === "number" ? raw[k] : fallback;
2503
+ return {
2504
+ timezone: String(raw["timezone"] ?? world.timezone),
2505
+ slot_minutes: num("slot_minutes", 30),
2506
+ buffer_minutes: num("buffer_minutes", 0),
2507
+ lead_minutes: num("lead_minutes", 0),
2508
+ max_per_day: num("max_per_day", 0),
2509
+ days: num("days", 14),
2510
+ windows: (raw["windows"] ?? []).map((w) => ({
2511
+ weekday: Number(w["weekday"] ?? 1),
2512
+ from: String(w["from"] ?? "09:00"),
2513
+ to: String(w["to"] ?? "17:00"),
2514
+ member_user_id: null
2515
+ }))
2516
+ };
2517
+ }
2518
+ function zoneOffset2(zone, at) {
2519
+ 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) }, {});
2520
+ return (Date.UTC(parts["year"], parts["month"] - 1, parts["day"], parts["hour"], parts["minute"]) - at) / 6e4;
2521
+ }
2522
+ function zonedInstant(zone, day, minutes) {
2523
+ const guess = day + minutes * 6e4;
2524
+ return guess - zoneOffset2(zone, guess - zoneOffset2(zone, guess) * 6e4) * 6e4;
2525
+ }
2526
+ function bookingSlots(world, table, a, days) {
2527
+ const zone = (() => {
2528
+ try {
2529
+ new Intl.DateTimeFormat("en-US", { timeZone: a.timezone });
2530
+ return a.timezone;
2531
+ } catch {
2532
+ return "UTC";
2533
+ }
2534
+ })();
2535
+ const taken = /* @__PURE__ */ new Set();
2536
+ for (const id of table.order) {
2537
+ for (const v of Object.values(table.rows.get(id) ?? {})) {
2538
+ if (typeof v === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(v)) taken.add(new Date(v).getTime());
2539
+ }
2540
+ }
2541
+ const toMin = (hhmm) => {
2542
+ const [h, m2] = hhmm.split(":").map(Number);
2543
+ return (h ?? 0) * 60 + (m2 ?? 0);
2544
+ };
2545
+ const [y, m, d] = world.today.split("-").map(Number);
2546
+ const start = Date.UTC(y, m - 1, d);
2547
+ const earliest = zonedInstant(zone, start, 9 * 60) + a.lead_minutes * 6e4;
2548
+ const step = Math.max(5, a.slot_minutes + a.buffer_minutes);
2549
+ const slots = [];
2550
+ for (let i = 0; i < Math.max(1, days); i += 1) {
2551
+ const day = start + i * DAY_MS;
2552
+ const weekday = new Date(day).getUTCDay();
2553
+ let today = 0;
2554
+ for (const w of a.windows.filter((x) => x.weekday === weekday)) {
2555
+ for (let t = toMin(w.from); t + a.slot_minutes <= toMin(w.to); t += step) {
2556
+ if (a.max_per_day > 0 && today >= a.max_per_day) break;
2557
+ const at = zonedInstant(zone, day, t);
2558
+ if (at < earliest) continue;
2559
+ today += 1;
2560
+ const iso = new Date(at).toISOString();
2561
+ slots.push({ key: iso, at: iso, taken: taken.has(at), member_user_id: null });
2562
+ }
2563
+ }
2564
+ }
2565
+ return slots;
2566
+ }
2427
2567
  var VIEWER = "viewer";
2428
2568
  function memoryDataSource(world) {
2429
2569
  const looks = /* @__PURE__ */ new Map();
@@ -2632,15 +2772,106 @@ function memoryDataSource(world) {
2632
2772
  record_stage_pending: () => ok([]),
2633
2773
  io_imports: () => ok([]),
2634
2774
  relation_words: (args) => ok(nameOf(String(args["p_value"] ?? ""))),
2775
+ // The read doors a form, a booking page and a dashboard are drawn from (lane CHAIR-GALLERY-3).
2635
2776
  forms: (args) => ok(
2636
- world.forms.filter((f) => !f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({ form_id: f.form_id, table_id: f.table_id, title: f.title, questions: f.questions, presentation: f.presentation, published_at: null, slug: null }))
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
+ submission_cap: null,
2785
+ responses: 0,
2786
+ in_table: 0,
2787
+ held: 0,
2788
+ rejected: 0,
2789
+ state: "open",
2790
+ quarantine_rule_id: null,
2791
+ notify_rule_id: null,
2792
+ questions: f.questions,
2793
+ presentation: { ...f.presentation, questions: f.presentation["questions"] ?? f.questions }
2794
+ }))
2637
2795
  ),
2796
+ form_preview_asks: (args) => {
2797
+ const t = tableOf(args);
2798
+ const values = args["p_values"] ?? {};
2799
+ return ok(
2800
+ (args["p_questions"] ?? []).map((q) => {
2801
+ const when = q["show_if"] ?? q["showIf"] ?? null;
2802
+ const asked = !when || !t ? true : rule(t, values, values, when) !== false;
2803
+ return { field_key: String(q["field"] ?? q["key"] ?? ""), asked, decided: true, said: null };
2804
+ })
2805
+ );
2806
+ },
2638
2807
  bookings: (args) => ok(
2639
- world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({ form_id: f.form_id, table_id: f.table_id, title: f.title, questions: f.questions, availability: f.booking, presentation: f.presentation, slug: null }))
2808
+ world.forms.filter((f) => f.booking && (!args["p_table_id"] || f.table_id === args["p_table_id"])).map((f) => ({
2809
+ form_id: f.form_id,
2810
+ table_id: f.table_id,
2811
+ title: f.title,
2812
+ slug: f.token,
2813
+ published_at: `${world.today}T09:00:00Z`,
2814
+ closed_at: null,
2815
+ slot_minutes: Number(f.booking["slot_minutes"] ?? 30),
2816
+ timezone: String(f.booking["timezone"] ?? world.timezone),
2817
+ slot_table_id: null,
2818
+ booked: 0,
2819
+ cancelled: 0,
2820
+ upcoming: 0,
2821
+ held: 0,
2822
+ next_at: null,
2823
+ state: "open"
2824
+ }))
2640
2825
  ),
2826
+ booking_public: (args) => {
2827
+ const f = world.forms.find((x) => x.form_id === args["p_form_id"] && x.booking);
2828
+ const t = f ? world.tableById.get(f.table_id) : void 0;
2829
+ if (!f || !t) return refuse("That booking page is not in this template.", "P0002");
2830
+ const availability = bookingAvailability(world, f.booking);
2831
+ return ok({
2832
+ form_id: f.form_id,
2833
+ organization_id: world.organization_id,
2834
+ table_id: t.id,
2835
+ title: f.title,
2836
+ presentation: { ...f.presentation, questions: f.questions },
2837
+ fields: t.fields.map((x) => ({ id: x.id, ...x.data })),
2838
+ honeypot_key: null,
2839
+ availability,
2840
+ slots: bookingSlots(world, t, availability, Number(args["p_days"] ?? availability.days)),
2841
+ state: "open",
2842
+ message: null
2843
+ });
2844
+ },
2641
2845
  dashboards: (args) => ok(
2642
- world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({ dashboard_id: d.dashboard_id, table_id: d.table_id, name: d.name, blocks: d.blocks, presentation: {} }))
2643
- )
2846
+ world.dashboards.filter((d) => !args["p_table_id"] || d.table_id === args["p_table_id"]).map((d) => ({
2847
+ dashboard_id: d.dashboard_id,
2848
+ table_id: d.table_id,
2849
+ name: d.name,
2850
+ blocks: d.blocks,
2851
+ presentation: {},
2852
+ block_count: d.blocks.length,
2853
+ version: 1,
2854
+ created_at: `${world.today}T09:00:00Z`,
2855
+ updated_at: `${world.today}T09:00:00Z`
2856
+ }))
2857
+ ),
2858
+ dashboard_run: (args) => {
2859
+ const d = world.dashboards.find((x) => x.dashboard_id === args["p_dashboard_id"]);
2860
+ if (!d) return refuse("That dashboard is not in this template.", "P0002");
2861
+ const canvas = args["p_filter"] ?? {};
2862
+ return ok({
2863
+ dashboard_id: d.dashboard_id,
2864
+ name: d.name,
2865
+ subject_table_id: d.table_id,
2866
+ presentation: {},
2867
+ filter: canvas,
2868
+ grain: null,
2869
+ compare: null,
2870
+ calendar: { time_zone: world.timezone, week_start: "monday" },
2871
+ blocks: d.blocks.map((b, i) => runBlock(world, d.table_id, b, canvas, i))
2872
+ });
2873
+ },
2874
+ dashboard_stuck: () => ok([])
2644
2875
  };
2645
2876
  const source = {
2646
2877
  world,