PageSourceSearch

https://splashiq.ai/downloads/splashiq-tenant.mjs

js splashiq.ai collected 2026-10-05 12:44:42 UTC 2,940 bytes, 70 lines download raw bytes

1#!/usr/bin/env node
2
3// Fixed SplashIQ origin and setup-only commands. Never uses a user/service JWT.
4import { readFile } from "node:fs/promises";
5
6const [command, ...args] = process.argv.slice(2);
7const usage = `Usage:
8  SPLASHIQ_SETUP_TOKEN=<token> node scripts/splashiq-tenant.mjs status
9  SPLASHIQ_SETUP_TOKEN=<token> node scripts/splashiq-tenant.mjs import-preview <setup.json>
10  SPLASHIQ_SETUP_TOKEN=<token> node scripts/splashiq-tenant.mjs import-commit <batch-id> <same-setup.json> --confirm
11  SPLASHIQ_SETUP_TOKEN=<token> node scripts/splashiq-tenant.mjs email-draft <draft.json>
12`;
13
14const token = process.env.SPLASHIQ_SETUP_TOKEN;
15if (!token || !/^si_setup_[0-9a-f-]{36}_[A-Za-z0-9_-]{43}$/.test(token)) {
16  process.stderr.write("Set a valid SPLASHIQ_SETUP_TOKEN from Settings → AI setup access.\n");
17  process.exitCode = 2;
18} else if (command === "status" && args.length === 0) {
19  await callSetup("/api/tenant/setup", "GET");
20} else if (command === "import-preview" && args.length === 1) {
21  const payload = await loadPayload(args[0]);
22  if (payload) await callSetup("/api/tenant/setup/imports", "POST", { action: "preview", payload });
23} else if (command === "import-commit" && args.length === 3
24  && /^[0-9a-f-]{36}$/.test(args[0]) && args[2] === "--confirm") {
25  const payload = await loadPayload(args[1]);
26  if (payload) await callSetup("/api/tenant/setup/imports", "POST", {
27    action: "commit", batch_id: args[0], payload,
28  });
29} else if (command === "email-draft" && args.length === 1) {
30  const payload = await loadPayload(args[0]);
31  if (payload) await callSetup("/api/tenant/setup/drafts", "POST", payload);
32} else {
33  process.stderr.write(usage);
34  process.exitCode = 2;
35}
36
37async function loadPayload(path) {
38  try {
39    const source = await readFile(path, "utf8");
40    if (Buffer.byteLength(source) > 90_000) throw new Error("Import is too large");
41    return JSON.parse(source);
42  } catch (error) {
43    process.stderr.write(`Could not read import file: ${error instanceof Error ? error.message : "unknown error"}\n`);
44    process.exitCode = 2;
45    return null;
46  }
47}
48
49async function callSetup(path, method, body) {
50  try {
51    const response = await fetch(`https://splashiq.ai${path}`, {
52      method,
53      headers: { Authorization: `Bearer ${token}`, ...(body ? { "Content-Type": "application/json" } : {}) },
54      body: body ? JSON.stringify(body) : undefined,
55      signal: AbortSignal.timeout(20_000),
56    });
57    const result = await response.json();
58    if (!response.ok) {
59      process.stderr.write(response.status === 401
60        ? "Setup token is invalid, expired, revoked, or lacks permission for this command.\n"
61        : `${JSON.stringify(result, null, 2)}\n`);
62      process.exitCode = 1;
63    } else {
64      process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
65    }
66  } catch {
67    process.stderr.write("Could not reach SplashIQ. Try again later.\n");
68    process.exitCode = 1;
69  }
70}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.