@automagik/omni 2.260731.3 → 2.260803.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/dist/sdk/index.js CHANGED
@@ -2290,12 +2290,216 @@ function createOmniClient(config) {
2290
2290
  raw: client
2291
2291
  };
2292
2292
  }
2293
+ // src/flow-builder.ts
2294
+ class FlowBuilderError extends Error {
2295
+ constructor(message) {
2296
+ super(message);
2297
+ this.name = "FlowBuilderError";
2298
+ }
2299
+ }
2300
+
2301
+ class FormBuilder {
2302
+ components = [];
2303
+ footerSet = false;
2304
+ textInput(name, label, opts = {}) {
2305
+ const { inputType, ...rest } = opts;
2306
+ this.components.push({ type: "TextInput", name, label, "input-type": inputType ?? "text", ...rest });
2307
+ return this;
2308
+ }
2309
+ textArea(name, label, opts = {}) {
2310
+ this.components.push({ type: "TextArea", name, label, ...opts });
2311
+ return this;
2312
+ }
2313
+ datePicker(name, label, opts = {}) {
2314
+ this.components.push({ type: "DatePicker", name, label, ...opts });
2315
+ return this;
2316
+ }
2317
+ optIn(name, label, opts = {}) {
2318
+ this.components.push({ type: "OptIn", name, label, ...opts });
2319
+ return this;
2320
+ }
2321
+ dropdown(name, label, dataSource, opts = {}) {
2322
+ this.components.push({ type: "Dropdown", name, label, "data-source": dataSource, ...opts });
2323
+ return this;
2324
+ }
2325
+ radioButtons(name, label, dataSource, opts = {}) {
2326
+ this.components.push({ type: "RadioButtonsGroup", name, label, "data-source": dataSource, ...opts });
2327
+ return this;
2328
+ }
2329
+ checkboxGroup(name, label, dataSource, opts = {}) {
2330
+ this.components.push({ type: "CheckboxGroup", name, label, "data-source": dataSource, ...opts });
2331
+ return this;
2332
+ }
2333
+ footerComplete(label, payload) {
2334
+ this.footer(label, { name: "complete", payload });
2335
+ return this;
2336
+ }
2337
+ footerDataExchange(label, payload = {}) {
2338
+ this.footer(label, { name: "data_exchange", payload });
2339
+ return this;
2340
+ }
2341
+ footerNavigate(label, nextScreen, payload = {}) {
2342
+ this.footer(label, { name: "navigate", next: { type: "screen", name: nextScreen }, payload });
2343
+ return this;
2344
+ }
2345
+ raw(component) {
2346
+ this.components.push(component);
2347
+ return this;
2348
+ }
2349
+ footer(label, action) {
2350
+ if (this.footerSet)
2351
+ throw new FlowBuilderError("a Form can only have one Footer");
2352
+ this.footerSet = true;
2353
+ this.components.push({ type: "Footer", label, "on-click-action": action });
2354
+ }
2355
+ }
2356
+
2357
+ class ScreenBuilder {
2358
+ id;
2359
+ components = [];
2360
+ constructor(id) {
2361
+ this.id = id;
2362
+ }
2363
+ heading(text) {
2364
+ this.components.push({ type: "TextHeading", text });
2365
+ return this;
2366
+ }
2367
+ subheading(text) {
2368
+ this.components.push({ type: "TextSubheading", text });
2369
+ return this;
2370
+ }
2371
+ body(text) {
2372
+ this.components.push({ type: "TextBody", text });
2373
+ return this;
2374
+ }
2375
+ caption(text) {
2376
+ this.components.push({ type: "TextCaption", text });
2377
+ return this;
2378
+ }
2379
+ richText(text) {
2380
+ this.components.push({ type: "RichText", text });
2381
+ return this;
2382
+ }
2383
+ image(src, opts = {}) {
2384
+ this.components.push({
2385
+ type: "Image",
2386
+ src,
2387
+ ...opts.height !== undefined ? { height: opts.height } : {},
2388
+ ...opts.scaleType ? { "scale-type": opts.scaleType } : {},
2389
+ ...opts.altText ? { "alt-text": opts.altText } : {}
2390
+ });
2391
+ return this;
2392
+ }
2393
+ form(name, define) {
2394
+ const builder = new FormBuilder;
2395
+ define(builder);
2396
+ this.components.push({ type: "Form", name, children: builder.components });
2397
+ return this;
2398
+ }
2399
+ footerNavigate(label, nextScreen, payload = {}) {
2400
+ this.components.push({
2401
+ type: "Footer",
2402
+ label,
2403
+ "on-click-action": { name: "navigate", next: { type: "screen", name: nextScreen }, payload }
2404
+ });
2405
+ return this;
2406
+ }
2407
+ footerComplete(label, payload) {
2408
+ this.components.push({ type: "Footer", label, "on-click-action": { name: "complete", payload } });
2409
+ return this;
2410
+ }
2411
+ footerDataExchange(label, payload = {}) {
2412
+ this.components.push({ type: "Footer", label, "on-click-action": { name: "data_exchange", payload } });
2413
+ return this;
2414
+ }
2415
+ raw(component) {
2416
+ this.components.push(component);
2417
+ return this;
2418
+ }
2419
+ }
2420
+
2421
+ class FlowBuilder {
2422
+ options;
2423
+ screens = [];
2424
+ constructor(options = {}) {
2425
+ this.options = options;
2426
+ }
2427
+ screen(id, optionsOrDefine, maybeDefine) {
2428
+ const options = typeof optionsOrDefine === "function" ? {} : optionsOrDefine;
2429
+ const define = typeof optionsOrDefine === "function" ? optionsOrDefine : maybeDefine;
2430
+ if (!define)
2431
+ throw new FlowBuilderError(`screen '${id}' needs a definition callback`);
2432
+ if (this.screens.some((s) => s.id === id))
2433
+ throw new FlowBuilderError(`duplicate screen id '${id}'`);
2434
+ const builder = new ScreenBuilder(id);
2435
+ define(builder);
2436
+ this.screens.push({ id, options, components: builder.components });
2437
+ return this;
2438
+ }
2439
+ build() {
2440
+ if (this.screens.length === 0)
2441
+ throw new FlowBuilderError("a flow needs at least one screen");
2442
+ const ids = new Set(this.screens.map((s) => s.id));
2443
+ if (!this.screens.some((s) => s.options.terminal)) {
2444
+ throw new FlowBuilderError("at least one screen must be terminal: true");
2445
+ }
2446
+ const routingModel = {};
2447
+ for (const screen of this.screens) {
2448
+ const hasRichText = screen.components.some((c) => c.type === "RichText");
2449
+ if (hasRichText && screen.components.some((c) => c.type !== "RichText" && c.type !== "Footer")) {
2450
+ throw new FlowBuilderError(`screen '${screen.id}': RichText must be the only component on the screen (Footer excepted)`);
2451
+ }
2452
+ const targets = [];
2453
+ const visit = (component) => {
2454
+ const action = component["on-click-action"];
2455
+ if (action?.name === "navigate") {
2456
+ const next = action.next;
2457
+ if (next?.type === "screen" && next.name) {
2458
+ if (!ids.has(next.name)) {
2459
+ throw new FlowBuilderError(`screen '${screen.id}': navigate targets unknown screen '${next.name}'`);
2460
+ }
2461
+ targets.push(next.name);
2462
+ }
2463
+ }
2464
+ const children = component.children;
2465
+ if (Array.isArray(children))
2466
+ for (const child of children)
2467
+ visit(child);
2468
+ };
2469
+ for (const component of screen.components)
2470
+ visit(component);
2471
+ routingModel[screen.id] = targets;
2472
+ }
2473
+ const json = {
2474
+ version: this.options.version ?? "6.3",
2475
+ ...this.options.dynamic ? { data_api_version: "3.0" } : {},
2476
+ routing_model: routingModel,
2477
+ screens: this.screens.map((screen) => ({
2478
+ id: screen.id,
2479
+ ...screen.options.title ? { title: screen.options.title } : {},
2480
+ ...screen.options.terminal ? { terminal: true } : {},
2481
+ ...screen.options.data ? { data: screen.options.data } : {},
2482
+ ...screen.options.refreshOnBack ? { refresh_on_back: true } : {},
2483
+ layout: { type: "SingleColumnLayout", children: screen.components }
2484
+ }))
2485
+ };
2486
+ return { json, flowJson: JSON.stringify(json) };
2487
+ }
2488
+ }
2489
+ function flow(options = {}) {
2490
+ return new FlowBuilder(options);
2491
+ }
2293
2492
 
2294
2493
  // src/index.ts
2295
2494
  var VERSION = "0.0.1";
2296
2495
  export {
2496
+ flow,
2297
2497
  createOmniClient,
2298
2498
  VERSION,
2499
+ ScreenBuilder,
2299
2500
  OmniConfigError,
2300
- OmniApiError
2501
+ OmniApiError,
2502
+ FormBuilder,
2503
+ FlowBuilderError,
2504
+ FlowBuilder
2301
2505
  };