lua-cli 3.39.4 → 3.41.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.
@@ -9,6 +9,7 @@ Complete reference for all lua-cli runtime APIs available in your tools, webhook
9
9
  When your code runs in the Lua platform (either in sandbox or production), you have access to powerful APIs for managing users, products, data, and more. These APIs are injected as globals into the VM execution environment.
10
10
 
11
11
  **Import APIs in your code:**
12
+
12
13
  ```typescript
13
14
  import { User, Products, Data, Jobs, AI } from 'lua-cli';
14
15
  ```
@@ -18,6 +19,7 @@ import { User, Products, Data, Jobs, AI } from 'lua-cli';
18
19
  ## Table of Contents
19
20
 
20
21
  ### Core Primitives
22
+
21
23
  - [LuaAgent](#luaagent) - Agent configuration
22
24
  - [LuaSkill](#luaskill) - Tool collections
23
25
  - [LuaTool](#luatool) - Individual tools
@@ -27,6 +29,7 @@ import { User, Products, Data, Jobs, AI } from 'lua-cli';
27
29
  - [PostProcessor](#postprocessor) - Response postprocessing
28
30
 
29
31
  ### Runtime APIs
32
+
30
33
  - [User API](#user-api) - User data management
31
34
  - [Products API](#products-api) - Product catalog
32
35
  - [Data API](#data-api) - Custom data storage
@@ -39,6 +42,7 @@ import { User, Products, Data, Jobs, AI } from 'lua-cli';
39
42
  - [Channels API](#channels-api) - Outbound channel sends
40
43
 
41
44
  ### Utilities
45
+
42
46
  - [env()](#env) - Environment variables
43
47
  - [Lua Runtime](#lua-runtime) - Request context
44
48
 
@@ -80,6 +84,7 @@ import {
80
84
  ### Common Patterns
81
85
 
82
86
  **Create a Tool:**
87
+
83
88
  ```typescript
84
89
  import { LuaTool } from 'lua-cli/skill';
85
90
  import { z } from 'zod';
@@ -96,6 +101,7 @@ export default class MyTool implements LuaTool {
96
101
  ```
97
102
 
98
103
  **Access User Data:**
104
+
99
105
  ```typescript
100
106
  import { User } from 'lua-cli';
101
107
 
@@ -105,6 +111,7 @@ await user.send([{ type: 'text', text: 'Hello!' }]);
105
111
  ```
106
112
 
107
113
  **Use Custom Storage:**
114
+
108
115
  ```typescript
109
116
  import { Data } from 'lua-cli';
110
117
 
@@ -124,6 +131,7 @@ Unified agent configuration that combines skills, webhooks, jobs, and processors
124
131
  **Documentation:** [docs/api/LuaAgent.md](./api/LuaAgent.md)
125
132
 
126
133
  **Quick Example:**
134
+
127
135
  ```typescript
128
136
  import { LuaAgent, LuaSkill } from 'lua-cli';
129
137
 
@@ -134,7 +142,7 @@ export const agent = new LuaAgent({
134
142
  webhooks: [webhook1],
135
143
  jobs: [job1],
136
144
  preProcessors: [preProcessor1],
137
- postProcessors: [postProcessor1]
145
+ postProcessors: [postProcessor1],
138
146
  });
139
147
  ```
140
148
 
@@ -147,6 +155,7 @@ Group related tools together with shared context.
147
155
  **Documentation:** [docs/api/LuaSkill.md](./api/LuaSkill.md)
148
156
 
149
157
  **Quick Example:**
158
+
150
159
  ```typescript
151
160
  import { LuaSkill } from 'lua-cli';
152
161
 
@@ -154,7 +163,7 @@ export default new LuaSkill({
154
163
  name: 'weather-skill',
155
164
  description: 'Weather information tools',
156
165
  context: 'Use these tools to get weather data',
157
- tools: [tool1, tool2]
166
+ tools: [tool1, tool2],
158
167
  });
159
168
  ```
160
169
 
@@ -167,6 +176,7 @@ Individual function your agent can call.
167
176
  **Documentation:** [docs/api/LuaTool.md](./api/LuaTool.md)
168
177
 
169
178
  **Quick Example:**
179
+
170
180
  ```typescript
171
181
  import { LuaTool } from 'lua-cli/skill';
172
182
  import { z } from 'zod';
@@ -176,7 +186,7 @@ export default class GetWeatherTool implements LuaTool {
176
186
  description = 'Get current weather';
177
187
 
178
188
  inputSchema = z.object({
179
- city: z.string()
189
+ city: z.string(),
180
190
  });
181
191
 
182
192
  async execute(input) {
@@ -194,6 +204,7 @@ HTTP endpoint for external integrations.
194
204
  **Documentation:** [docs/api/LuaWebhook.md](./api/LuaWebhook.md)
195
205
 
196
206
  **Quick Example:**
207
+
197
208
  ```typescript
198
209
  import { LuaWebhook } from 'lua-cli';
199
210
  import { z } from 'zod';
@@ -204,12 +215,12 @@ export default new LuaWebhook({
204
215
 
205
216
  bodySchema: z.object({
206
217
  orderId: z.string(),
207
- amount: z.number()
218
+ amount: z.number(),
208
219
  }),
209
220
 
210
221
  execute: async ({ body, headers, query }) => {
211
222
  return { status: 200, body: { received: true } };
212
- }
223
+ },
213
224
  });
214
225
  ```
215
226
 
@@ -222,6 +233,7 @@ Scheduled task that runs automatically.
222
233
  **Documentation:** [docs/api/LuaJob.md](./api/LuaJob.md)
223
234
 
224
235
  **Quick Example:**
236
+
225
237
  ```typescript
226
238
  import { LuaJob } from 'lua-cli';
227
239
 
@@ -231,12 +243,12 @@ export default new LuaJob({
231
243
 
232
244
  schedule: {
233
245
  type: 'cron',
234
- pattern: '0 0 * * *' // Midnight daily
246
+ pattern: '0 0 * * *', // Midnight daily
235
247
  },
236
248
 
237
249
  execute: async (job) => {
238
250
  return { success: true, deleted: 42 };
239
- }
251
+ },
240
252
  });
241
253
  ```
242
254
 
@@ -249,6 +261,7 @@ Filter or modify messages before they reach your agent.
249
261
  **Documentation:** [docs/api/PreProcessor.md](./api/PreProcessor.md)
250
262
 
251
263
  **Quick Example:**
264
+
252
265
  ```typescript
253
266
  import { PreProcessor } from 'lua-cli';
254
267
 
@@ -261,7 +274,7 @@ export default new PreProcessor({
261
274
  return { action: 'BLOCK' };
262
275
  }
263
276
  return { action: 'PROCEED' };
264
- }
277
+ },
265
278
  });
266
279
  ```
267
280
 
@@ -274,6 +287,7 @@ Transform or format agent responses.
274
287
  **Documentation:** [docs/api/PostProcessor.md](./api/PostProcessor.md)
275
288
 
276
289
  **Quick Example:**
290
+
277
291
  ```typescript
278
292
  import { PostProcessor } from 'lua-cli';
279
293
 
@@ -283,7 +297,7 @@ export default new PostProcessor({
283
297
 
284
298
  execute: async (response) => {
285
299
  return response.toUpperCase() + ' 🎉';
286
- }
300
+ },
287
301
  });
288
302
  ```
289
303
 
@@ -298,12 +312,14 @@ Access and manage user data.
298
312
  **Documentation:** [docs/api/User.md](./api/User.md)
299
313
 
300
314
  **Methods:**
315
+
301
316
  - `User.get()` - Get current user
302
317
  - `user.update(data)` - Update user data
303
318
  - `user.send(messages)` - Send messages to user
304
319
  - `user.getChatHistory()` - Get conversation history
305
320
 
306
321
  **Example:**
322
+
307
323
  ```typescript
308
324
  import { User } from 'lua-cli';
309
325
 
@@ -314,7 +330,7 @@ await user.update({ preferences: 'dark-mode' });
314
330
 
315
331
  await user.send([
316
332
  { type: 'text', text: 'Hello!' },
317
- { type: 'image', url: 'https://example.com/image.jpg' }
333
+ { type: 'image', url: 'https://example.com/image.jpg' },
318
334
  ]);
319
335
 
320
336
  const history = await user.getChatHistory();
@@ -329,6 +345,7 @@ Manage product catalog.
329
345
  **Documentation:** [docs/api/Products.md](./api/Products.md)
330
346
 
331
347
  **Methods:**
348
+
332
349
  - `Products.get(filter?)` - List products
333
350
  - `Products.getById(id)` - Get single product
334
351
  - `Products.search(query, filter?)` - Search products
@@ -337,6 +354,7 @@ Manage product catalog.
337
354
  - `product.delete()` - Delete product
338
355
 
339
356
  **Example:**
357
+
340
358
  ```typescript
341
359
  import { Products } from 'lua-cli';
342
360
 
@@ -346,7 +364,7 @@ const products = await Products.get();
346
364
  // Search products
347
365
  const results = await Products.search('laptop', {
348
366
  category: 'electronics',
349
- inStock: true
367
+ inStock: true,
350
368
  });
351
369
 
352
370
  // Create product
@@ -354,7 +372,7 @@ const product = await Products.create({
354
372
  name: 'MacBook Pro',
355
373
  price: 2499,
356
374
  category: 'electronics',
357
- stock: 10
375
+ stock: 10,
358
376
  });
359
377
 
360
378
  // Update
@@ -373,6 +391,7 @@ Custom data storage with vector search.
373
391
  **Documentation:** [docs/api/Data.md](./api/Data.md)
374
392
 
375
393
  **Methods:**
394
+
376
395
  - `Data.get(collection, filter?)` - List entries
377
396
  - `Data.getEntry(collection, id)` - Get single entry
378
397
  - `Data.search(collection, query)` - Vector search
@@ -381,6 +400,7 @@ Custom data storage with vector search.
381
400
  - `entry.delete()` - Delete entry
382
401
 
383
402
  **Example:**
403
+
384
404
  ```typescript
385
405
  import { Data } from 'lua-cli';
386
406
 
@@ -388,7 +408,7 @@ import { Data } from 'lua-cli';
388
408
  await Data.create('notes', {
389
409
  title: 'Meeting Notes',
390
410
  content: 'Discussed Q1 roadmap...',
391
- tags: ['meeting', 'planning']
411
+ tags: ['meeting', 'planning'],
392
412
  });
393
413
 
394
414
  // List
@@ -414,6 +434,7 @@ Shopping cart management.
414
434
  **Documentation:** [docs/api/Baskets.md](./api/Baskets.md)
415
435
 
416
436
  **Methods:**
437
+
417
438
  - `Baskets.get()` - List baskets
418
439
  - `Baskets.create()` - Create basket
419
440
  - `Baskets.getById(id)` - Get basket
@@ -423,6 +444,7 @@ Shopping cart management.
423
444
  - `basket.placeOrder()` - Convert to order
424
445
 
425
446
  **Example:**
447
+
426
448
  ```typescript
427
449
  import { Baskets } from 'lua-cli';
428
450
 
@@ -433,7 +455,7 @@ const basket = await Baskets.create();
433
455
  await basket.addItem({
434
456
  productId: 'prod-123',
435
457
  quantity: 2,
436
- price: 29.99
458
+ price: 29.99,
437
459
  });
438
460
 
439
461
  // Place order
@@ -449,6 +471,7 @@ Order management and fulfillment.
449
471
  **Documentation:** [docs/api/Orders.md](./api/Orders.md)
450
472
 
451
473
  **Methods:**
474
+
452
475
  - `Orders.get(filter?)` - List orders
453
476
  - `Orders.getById(id)` - Get order
454
477
  - `Orders.create(data)` - Create order
@@ -456,6 +479,7 @@ Order management and fulfillment.
456
479
  - `order.updateData(data)` - Update order data
457
480
 
458
481
  **Example:**
482
+
459
483
  ```typescript
460
484
  import { Orders } from 'lua-cli';
461
485
 
@@ -479,6 +503,7 @@ Create jobs dynamically from tools.
479
503
  **Documentation:** [docs/api/Jobs.md](./api/Jobs.md)
480
504
 
481
505
  **Methods:**
506
+
482
507
  - `Jobs.create(config)` - Create job
483
508
  - `Jobs.getJob(jobId)` - Get job
484
509
  - `Jobs.getAll()` - List all jobs
@@ -486,6 +511,7 @@ Create jobs dynamically from tools.
486
511
  - `job.delete()` - Delete job
487
512
 
488
513
  **Example:**
514
+
489
515
  ```typescript
490
516
  import { Jobs } from 'lua-cli';
491
517
 
@@ -495,16 +521,18 @@ const job = await Jobs.create({
495
521
  metadata: { message: 'Meeting in 1 hour' },
496
522
  schedule: {
497
523
  type: 'once',
498
- executeAt: new Date(Date.now() + 3600000)
524
+ executeAt: new Date(Date.now() + 3600000),
499
525
  },
500
526
  execute: async (job) => {
501
527
  const user = await job.user();
502
- await user.send([{
503
- type: 'text',
504
- text: job.metadata.message
505
- }]);
528
+ await user.send([
529
+ {
530
+ type: 'text',
531
+ text: job.metadata.message,
532
+ },
533
+ ]);
506
534
  return { success: true };
507
- }
535
+ },
508
536
  });
509
537
  ```
510
538
 
@@ -517,15 +545,17 @@ Generate AI text responses.
517
545
  **Documentation:** [docs/api/AI.md](./api/AI.md)
518
546
 
519
547
  **Methods:**
548
+
520
549
  - `AI.generate(prompt, options?)` - Generate text
521
550
 
522
551
  **Example:**
552
+
523
553
  ```typescript
524
554
  import { AI } from 'lua-cli';
525
555
 
526
556
  const response = await AI.generate('Summarize this text: ...', {
527
557
  maxTokens: 100,
528
- temperature: 0.7
558
+ temperature: 0.7,
529
559
  });
530
560
 
531
561
  console.log(response.text);
@@ -540,11 +570,13 @@ Send WhatsApp template messages.
540
570
  **Documentation:** [docs/api/Templates.md](./api/Templates.md)
541
571
 
542
572
  **Methods:**
573
+
543
574
  - `Templates.whatsapp.list()` - List templates
544
575
  - `Templates.whatsapp.get(name)` - Get template
545
576
  - `Templates.whatsapp.send(config)` - Send template
546
577
 
547
578
  **Example:**
579
+
548
580
  ```typescript
549
581
  import { Templates } from 'lua-cli';
550
582
 
@@ -555,8 +587,8 @@ await Templates.whatsapp.send({
555
587
  to: '+1234567890',
556
588
  parameters: {
557
589
  order_id: '12345',
558
- amount: '$99.99'
559
- }
590
+ amount: '$99.99',
591
+ },
560
592
  });
561
593
  ```
562
594
 
@@ -569,16 +601,18 @@ Upload and download files.
569
601
  **Documentation:** [docs/api/CDN.md](./api/CDN.md)
570
602
 
571
603
  **Methods:**
604
+
572
605
  - `CDN.upload(file, options)` - Upload file
573
606
  - `CDN.get(fileId)` - Get file URL
574
607
 
575
608
  **Example:**
609
+
576
610
  ```typescript
577
611
  import { CDN } from 'lua-cli';
578
612
 
579
613
  const result = await CDN.upload(fileBuffer, {
580
614
  filename: 'report.pdf',
581
- contentType: 'application/pdf'
615
+ contentType: 'application/pdf',
582
616
  });
583
617
 
584
618
  const url = await CDN.get(result.fileId);
@@ -595,11 +629,13 @@ A successful send with a memory write failure returns `{ delivered: true, persis
595
629
  this is HTTP 200 and is never thrown as an error.
596
630
 
597
631
  **Methods:**
632
+
598
633
  - `Channels.send(input)` - Send a text message on any channel
599
634
  - `Channels.whatsapp.sendTemplate(input)` - Send a WhatsApp Business template
600
635
  - `Channels.email.send(input)` - Send an email
601
636
 
602
637
  **Examples:**
638
+
603
639
  ```typescript
604
640
  import { Channels } from 'lua-cli';
605
641
 
@@ -638,6 +674,7 @@ if (!result.persisted) {
638
674
  Access environment variables.
639
675
 
640
676
  **Usage:**
677
+
641
678
  ```typescript
642
679
  import { env } from 'lua-cli';
643
680
 
@@ -646,6 +683,7 @@ const baseUrl = env('BASE_URL') || 'https://api.example.com';
646
683
  ```
647
684
 
648
685
  **Setting Environment Variables:**
686
+
649
687
  ```bash
650
688
  # Via CLI
651
689
  lua env set OPENAI_API_KEY sk-...
@@ -661,6 +699,7 @@ OPENAI_API_KEY=sk-...
661
699
  Access request context information.
662
700
 
663
701
  **Usage:**
702
+
664
703
  ```typescript
665
704
  import { Lua } from 'lua-cli';
666
705
 
@@ -675,8 +714,31 @@ if (Lua.request.webhook) {
675
714
  ```
676
715
 
677
716
  **Properties:**
717
+
678
718
  - `Lua.request.channel` - Channel type (`'whatsapp'`, `'web'`, `'api'`)
679
719
  - `Lua.request.webhook` - Webhook info (if running in webhook)
720
+ - `Lua.request.invokedBy` - Present only when **another agent** created this turn through `Agents.invoke`:
721
+ `{ agentId, supervisor, scopes, delegatedUserId? }`. Verified by the platform, never caller-supplied.
722
+ - `supervisor` is true only when an org admin granted the caller `supervision:act` on this agent. Observe, preview and release grants do not set it.
723
+ - `scopes` lists the caller's supervision scopes on this agent. It is `[]` on version-preview turns.
724
+ - `delegatedUserId` is set when the caller passed `input.userId`.
725
+ - The field is absent on user, channel, job, webhook and self-invoked turns, and offline in `lua test`.
726
+
727
+ **Gating writes on agent invocation.** Treat a turn with `invokedBy` as agent-initiated. A mutating tool should
728
+ refuse it unless `invokedBy.supervisor === true` and the change is in the tool's supervisor allowlist. A
729
+ `delegatedUserId` never grants owner rights. Read it defensively, since older runtimes do not set it:
730
+
731
+ ```typescript
732
+ const invokedBy = (Lua.request as any).invokedBy;
733
+ if (invokedBy && !invokedBy.supervisor) {
734
+ return { refused: 'agent-invocation-not-authorised' };
735
+ }
736
+ ```
737
+
738
+ A turn created by **another** agent accepts only `messages`/`prompt`, `threadId`, `runtimeContext`, `webhookPayload` and the reasoning `effort`.
739
+
740
+ - The platform drops every other field: the persona (`systemPrompt`), `model`, tool scoping, version preview, workflow role and billing identities.
741
+ - It also resets a platform channel (`workflow`/`task`/`trigger`) to `agent-invocation`.
680
742
 
681
743
  ---
682
744
 
@@ -686,14 +748,14 @@ if (Lua.request.webhook) {
686
748
 
687
749
  These are returned by API calls and provide instance methods:
688
750
 
689
- | Instance | Methods | Description |
690
- |----------|---------|-------------|
691
- | `UserDataInstance` | `update()`, `send()`, `save()` | User with data access |
692
- | `ProductInstance` | `update()`, `delete()`, `save()` | Product with CRUD |
693
- | `BasketInstance` | `addItem()`, `removeItem()`, `placeOrder()` | Shopping cart |
694
- | `OrderInstance` | `updateStatus()`, `updateData()` | Order management |
695
- | `DataEntryInstance` | `update()`, `delete()`, `save()` | Custom data entry |
696
- | `JobInstance` | `user()`, `delete()` | Job with metadata |
751
+ | Instance | Methods | Description |
752
+ | ------------------- | ------------------------------------------- | --------------------- |
753
+ | `UserDataInstance` | `update()`, `send()`, `save()` | User with data access |
754
+ | `ProductInstance` | `update()`, `delete()`, `save()` | Product with CRUD |
755
+ | `BasketInstance` | `addItem()`, `removeItem()`, `placeOrder()` | Shopping cart |
756
+ | `OrderInstance` | `updateStatus()`, `updateData()` | Order management |
757
+ | `DataEntryInstance` | `update()`, `delete()`, `save()` | Custom data entry |
758
+ | `JobInstance` | `user()`, `delete()` | Job with metadata |
697
759
 
698
760
  ### Enums
699
761
 
@@ -703,7 +765,7 @@ enum BasketStatus {
703
765
  ACTIVE = 'ACTIVE',
704
766
  CHECKED_OUT = 'CHECKED_OUT',
705
767
  ABANDONED = 'ABANDONED',
706
- EXPIRED = 'EXPIRED'
768
+ EXPIRED = 'EXPIRED',
707
769
  }
708
770
 
709
771
  // Order status
@@ -711,7 +773,7 @@ enum OrderStatus {
711
773
  PENDING = 'PENDING',
712
774
  CONFIRMED = 'CONFIRMED',
713
775
  FULFILLED = 'FULFILLED',
714
- CANCELLED = 'CANCELLED'
776
+ CANCELLED = 'CANCELLED',
715
777
  }
716
778
  ```
717
779
 
@@ -719,38 +781,42 @@ enum OrderStatus {
719
781
 
720
782
  ## Complete API Index
721
783
 
722
- | API | Purpose | Key Methods |
723
- |-----|---------|-------------|
724
- | [User](./api/User.md) | User data | `get()`, `update()`, `send()` |
725
- | [Products](./api/Products.md) | Product catalog | `get()`, `search()`, `create()` |
726
- | [Data](./api/Data.md) | Custom storage | `get()`, `search()`, `create()` |
727
- | [Baskets](./api/Baskets.md) | Shopping carts | `create()`, `addItem()`, `placeOrder()` |
728
- | [Orders](./api/Orders.md) | Order management | `get()`, `updateStatus()` |
729
- | [Jobs](./api/Jobs.md) | Dynamic jobs | `create()`, `getAll()` |
730
- | [AI](./api/AI.md) | AI generation | `generate()` |
731
- | [Templates](./api/Templates.md) | WhatsApp templates | `list()`, `send()` |
732
- | [CDN](./api/CDN.md) | File storage | `upload()`, `get()` |
784
+ | API | Purpose | Key Methods |
785
+ | ------------------------------- | ------------------ | --------------------------------------- |
786
+ | [User](./api/User.md) | User data | `get()`, `update()`, `send()` |
787
+ | [Products](./api/Products.md) | Product catalog | `get()`, `search()`, `create()` |
788
+ | [Data](./api/Data.md) | Custom storage | `get()`, `search()`, `create()` |
789
+ | [Baskets](./api/Baskets.md) | Shopping carts | `create()`, `addItem()`, `placeOrder()` |
790
+ | [Orders](./api/Orders.md) | Order management | `get()`, `updateStatus()` |
791
+ | [Jobs](./api/Jobs.md) | Dynamic jobs | `create()`, `getAll()` |
792
+ | [AI](./api/AI.md) | AI generation | `generate()` |
793
+ | [Templates](./api/Templates.md) | WhatsApp templates | `list()`, `send()` |
794
+ | [CDN](./api/CDN.md) | File storage | `upload()`, `get()` |
733
795
 
734
796
  ---
735
797
 
736
798
  ## Usage by Category
737
799
 
738
800
  ### Building an Agent
801
+
739
802
  1. [LuaAgent](./api/LuaAgent.md) - Configure agent
740
803
  2. [LuaSkill](./api/LuaSkill.md) - Organize tools
741
804
  3. [LuaTool](./api/LuaTool.md) - Create tools
742
805
 
743
806
  ### E-commerce
807
+
744
808
  1. [Products API](./api/Products.md) - Manage catalog
745
809
  2. [Baskets API](./api/Baskets.md) - Shopping carts
746
810
  3. [Orders API](./api/Orders.md) - Process orders
747
811
 
748
812
  ### Automation
813
+
749
814
  1. [LuaJob](./api/LuaJob.md) - Scheduled tasks
750
815
  2. [Jobs API](./api/Jobs.md) - Dynamic jobs
751
816
  3. [LuaWebhook](./api/LuaWebhook.md) - HTTP triggers
752
817
 
753
818
  ### Data Management
819
+
754
820
  1. [User API](./api/User.md) - User data
755
821
  2. [Data API](./api/Data.md) - Custom storage
756
822
  3. [CDN API](./api/CDN.md) - File storage
@@ -762,6 +828,7 @@ enum OrderStatus {
762
828
  ### Error Handling
763
829
 
764
830
  Always wrap API calls in try-catch:
831
+
765
832
  ```typescript
766
833
  try {
767
834
  const user = await User.get();
@@ -775,6 +842,7 @@ try {
775
842
  ### Type Safety
776
843
 
777
844
  Use TypeScript types for better IDE support:
845
+
778
846
  ```typescript
779
847
  import { UserDataInstance, ProductInstance } from 'lua-cli';
780
848
 
@@ -785,6 +853,7 @@ const product: ProductInstance = await Products.getById('prod-123');
785
853
  ### Environment Variables
786
854
 
787
855
  Never hardcode secrets:
856
+
788
857
  ```typescript
789
858
  // ❌ Bad
790
859
  const apiKey = 'sk-1234567890';
@@ -797,6 +866,7 @@ const apiKey = env('OPENAI_API_KEY');
797
866
  ### Async/Await
798
867
 
799
868
  All API calls are async:
869
+
800
870
  ```typescript
801
871
  // ❌ Bad (missing await)
802
872
  const user = User.get();