@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.
@@ -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) => ({ form_id: f.form_id, table_id: f.table_id, title: f.title, questions: f.questions, presentation: f.presentation, published_at: null, slug: null }))
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) => ({ form_id: f.form_id, table_id: f.table_id, title: f.title, questions: f.questions, availability: f.booking, presentation: f.presentation, 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
+ 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) => ({ dashboard_id: d.dashboard_id, table_id: d.table_id, name: d.name, blocks: d.blocks, presentation: {} }))
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,