@rippling/rippling-sdk 0.2.0-alpha.68 → 0.2.0-alpha.70

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.
Files changed (42) hide show
  1. package/examples/manifest/dental-practice-management/dental-practice-management.ts +125 -1
  2. package/examples/manifest/dental-practice-management/functions/chair-schedule.ts +4 -4
  3. package/examples/manifest/dental-practice-management/functions/complete-visit.ts +121 -0
  4. package/examples/manifest/dental-practice-management/functions/operatory-list.ts +4 -4
  5. package/examples/manifest/dental-practice-management/functions/patient-list.ts +4 -4
  6. package/examples/manifest/dental-practice-management/functions/treatment-plan-list.ts +4 -4
  7. package/examples/manifest/gym-membership-management/functions/check-in-desk.ts +4 -4
  8. package/examples/manifest/gym-membership-management/functions/member-list.ts +4 -4
  9. package/examples/manifest/gym-membership-management/functions/today-schedule.ts +4 -4
  10. package/examples/manifest/gym-membership-management/functions/trainer-list.ts +4 -4
  11. package/examples/manifest/simple-todo-app/functions/todo-list.ts +4 -4
  12. package/examples/manifest/todo-app-without-object-list-view/functions/todo-page.ts +17 -7
  13. package/functions.d.mts +44 -1
  14. package/functions.d.mts.map +1 -1
  15. package/functions.d.ts +44 -1
  16. package/functions.d.ts.map +1 -1
  17. package/functions.js.map +1 -1
  18. package/functions.mjs.map +1 -1
  19. package/lib/manifest/custom-object-page-layout.d.mts +3 -3
  20. package/lib/manifest/custom-object-page-layout.d.mts.map +1 -1
  21. package/lib/manifest/custom-object-page-layout.d.ts +3 -3
  22. package/lib/manifest/custom-object-page-layout.d.ts.map +1 -1
  23. package/lib/manifest/custom-object-page-layout.js +7 -3
  24. package/lib/manifest/custom-object-page-layout.js.map +1 -1
  25. package/lib/manifest/custom-object-page-layout.mjs +7 -3
  26. package/lib/manifest/custom-object-page-layout.mjs.map +1 -1
  27. package/lib/manifest/index.d.mts +1 -1
  28. package/lib/manifest/index.d.mts.map +1 -1
  29. package/lib/manifest/index.d.ts +1 -1
  30. package/lib/manifest/index.d.ts.map +1 -1
  31. package/lib/manifest/index.js.map +1 -1
  32. package/lib/manifest/index.mjs.map +1 -1
  33. package/package.json +1 -1
  34. package/src/functions.md +26 -0
  35. package/src/functions.ts +66 -1
  36. package/src/lib/manifest/custom-object-page-layout.ts +13 -7
  37. package/src/lib/manifest/index.ts +0 -1
  38. package/src/version.ts +1 -1
  39. package/version.d.mts +1 -1
  40. package/version.d.ts +1 -1
  41. package/version.js +1 -1
  42. package/version.mjs +1 -1
@@ -3,6 +3,7 @@
3
3
  * with status, treatment plans, rollups, and an SDUI ObjectListView tab for appointments.
4
4
  *
5
5
  * dental_patient__c ← chart: demographics, allergies, notes
6
+ * dental_provider__c ← providers selectable for appointments
6
7
  * dental_operatory__c ← chair / room (parent for same-day board rollups)
7
8
  * dental_appointment__c ← child of operatory; patient lookup, time, status, visit type
8
9
  * dental_treatment_plan__c ← child of patient; plan status, procedures, estimates
@@ -146,6 +147,50 @@ const patientLabelField = new FormulaField(patientObj, {
146
147
  section: patientIdentitySection,
147
148
  });
148
149
 
150
+ // ── Provider ────────────────────────────────────────────────────────────────
151
+ const providerObj = new CustomObject(manifest, {
152
+ apiName: 'dental_provider__c',
153
+ name: 'Provider',
154
+ pluralLabel: 'Providers',
155
+ category: dentalCategory,
156
+ description: 'Clinicians who can be assigned to appointment blocks',
157
+ icon: { emoji: '🧑‍⚕️' },
158
+ });
159
+
160
+ const providerSection = new CustomObjectFieldSection(providerObj, {
161
+ name: 'Provider',
162
+ sectionId: 'sec_provider_info',
163
+ });
164
+
165
+ const providerNameField = providerObj.standardFields.name;
166
+
167
+ const providerStatusField = new SelectField(providerObj, {
168
+ apiName: 'provider_status__c',
169
+ displayName: 'Status',
170
+ description: 'Whether this provider is active in the practice',
171
+ options: ['Active', 'On leave', 'Inactive'],
172
+ required: true,
173
+ section: providerSection,
174
+ });
175
+
176
+ const providerBookingStatusField = new SelectField(providerObj, {
177
+ apiName: 'booking_status__c',
178
+ displayName: 'Booking status',
179
+ description: 'Whether scheduling should offer this provider for new appointments',
180
+ options: ['Open', 'Limited', 'Closed'],
181
+ required: true,
182
+ section: providerSection,
183
+ });
184
+
185
+ const providerNextAvailableDaysField = new NumberField(providerObj, {
186
+ apiName: 'next_available_days__c',
187
+ displayName: 'Next available (days)',
188
+ description: 'Estimated days until this provider has an open appointment slot',
189
+ decimalPlaces: 0,
190
+ required: true,
191
+ section: providerSection,
192
+ });
193
+
149
194
  // ── Operatory (chair) ─────────────────────────────────────────────────────────
150
195
  const operatoryObj = new CustomObject(manifest, {
151
196
  apiName: 'dental_operatory__c',
@@ -230,6 +275,18 @@ const apptPatientRef = new LookupField(apptObj, {
230
275
  section: apptPatientSection,
231
276
  });
232
277
 
278
+ const apptProviderRef = new LookupField(apptObj, {
279
+ apiName: 'provider_ref__c',
280
+ displayName: 'Provider',
281
+ target: providerObj,
282
+ relatedDataLabel: 'Appointments',
283
+ required: true,
284
+ lookup_filter_rql_condition:
285
+ "((provider_status__c == 'Active') AND (next_available_days__c <= 14) AND (booking_status__c != 'Closed'))",
286
+ description: 'Provider assigned to this visit (active and bookable within two weeks)',
287
+ section: apptPatientSection,
288
+ });
289
+
233
290
  const apptVisitTypeField = new SelectField(apptObj, {
234
291
  apiName: 'visit_type__c',
235
292
  displayName: 'Visit type',
@@ -402,6 +459,22 @@ new ListViewDef(patientObj, {
402
459
  objectScope: 'all',
403
460
  });
404
461
 
462
+ new ListViewDef(providerObj, {
463
+ viewId: 'view_dental_providers',
464
+ name: 'All providers',
465
+ description: 'Provider directory with appointment booking fields',
466
+ fields: [
467
+ providerNameField,
468
+ providerStatusField,
469
+ providerBookingStatusField,
470
+ providerNextAvailableDaysField,
471
+ ],
472
+ orderBy: 'name',
473
+ sortOrder: 'ASC',
474
+ isPublic: true,
475
+ objectScope: 'all',
476
+ });
477
+
405
478
  new ListViewDef(operatoryObj, {
406
479
  viewId: 'view_dental_all_operatories',
407
480
  name: 'All operatories',
@@ -423,6 +496,7 @@ new ListViewDef(apptObj, {
423
496
  apptStartField,
424
497
  apptDurationMins,
425
498
  apptPatientRef,
499
+ apptProviderRef,
426
500
  apptVisitTypeField,
427
501
  apptStatusField,
428
502
  apptBoardLabel,
@@ -490,6 +564,37 @@ new CustomObjectPageLayout(patientObj, {
490
564
  visibilityConditions: {},
491
565
  });
492
566
 
567
+ new CustomObjectPageLayout(providerObj, {
568
+ apiName: 'default',
569
+ name: 'Provider',
570
+ layoutId: 'layout_dental_provider',
571
+ tabEdits: {
572
+ newTabs: [
573
+ {
574
+ key: 'provider',
575
+ name: 'Provider',
576
+ type: 'tab_with_sections',
577
+ sections: [
578
+ {
579
+ name: 'Booking',
580
+ type: 'fields_section',
581
+ section: providerSection,
582
+ fields: [
583
+ { field: providerNameField, editable: true },
584
+ providerStatusField,
585
+ providerBookingStatusField,
586
+ providerNextAvailableDaysField,
587
+ ],
588
+ },
589
+ ],
590
+ },
591
+ ],
592
+ systemTabEdits: {},
593
+ tabsOrder: ['provider'],
594
+ },
595
+ visibilityConditions: {},
596
+ });
597
+
493
598
  new CustomObjectPageLayout(operatoryObj, {
494
599
  apiName: 'default',
495
600
  name: 'Operatory',
@@ -516,6 +621,15 @@ new CustomObjectPageLayout(operatoryObj, {
516
621
  visibilityConditions: {},
517
622
  });
518
623
 
624
+ const completeVisitFn = new ManifestFunction(manifest, {
625
+ apiName: 'dental_complete_visit_fn',
626
+ name: 'completeVisit',
627
+ description: 'Detail-view action that completes an appointment and drafts follow-up treatment',
628
+ code: fs.readFileSync(path.join(__dirname, 'functions', 'complete-visit.ts'), 'utf-8'),
629
+ dependencies: { '@rippling/rippling-sdk': '^0.2.0-alpha.65' },
630
+ isAsync: false,
631
+ });
632
+
519
633
  new CustomObjectPageLayout(apptObj, {
520
634
  apiName: 'default',
521
635
  name: 'Appointment',
@@ -537,7 +651,14 @@ new CustomObjectPageLayout(apptObj, {
537
651
  name: 'Patient & status',
538
652
  type: 'fields_section',
539
653
  section: apptPatientSection,
540
- fields: [apptPatientRef, apptVisitTypeField, apptStatusField, apptBoardLabel, apptClinicalNotes],
654
+ fields: [
655
+ apptPatientRef,
656
+ apptProviderRef,
657
+ apptVisitTypeField,
658
+ apptStatusField,
659
+ apptBoardLabel,
660
+ apptClinicalNotes,
661
+ ],
541
662
  },
542
663
  ],
543
664
  },
@@ -545,6 +666,9 @@ new CustomObjectPageLayout(apptObj, {
545
666
  systemTabEdits: {},
546
667
  tabsOrder: ['visit'],
547
668
  },
669
+ headerEdits: {
670
+ buttons: [completeVisitFn],
671
+ },
548
672
  visibilityConditions: {},
549
673
  });
550
674
 
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'dental_appointment__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -0,0 +1,121 @@
1
+ import RipplingSDK, {
2
+ DetailViewActionFunctionEvent,
3
+ FunctionContext,
4
+ FunctionResponse,
5
+ } from '@rippling/rippling-sdk';
6
+ import type { CustomObjectDataRow } from '@rippling/rippling-sdk/resources/custom-objects/records';
7
+
8
+ const APPOINTMENT_OBJECT_API_NAME = 'dental_appointment__c';
9
+ const TREATMENT_PLAN_OBJECT_API_NAME = 'dental_treatment_plan__c';
10
+
11
+ type CompleteVisitParameters = {
12
+ nextStepSummary?: string;
13
+ };
14
+
15
+ type CompleteVisitEvent = DetailViewActionFunctionEvent<
16
+ CompleteVisitParameters,
17
+ typeof APPOINTMENT_OBJECT_API_NAME,
18
+ 'dental_complete_visit_fn',
19
+ 'layout_dental_appointment'
20
+ >;
21
+
22
+ type CompleteVisitResponse = {
23
+ appointmentId: string;
24
+ treatmentPlanId?: string;
25
+ message: string;
26
+ };
27
+
28
+ function createClient(context: FunctionContext): RipplingSDK {
29
+ return new RipplingSDK({
30
+ bearerToken: context.env.rippling_user_bearer_token,
31
+ });
32
+ }
33
+
34
+ function stringValue(record: CustomObjectDataRow, key: string): string {
35
+ const value = record[key];
36
+ return typeof value === 'string' ? value : '';
37
+ }
38
+
39
+ function lookupId(record: CustomObjectDataRow, key: string): string | undefined {
40
+ const value = record[key];
41
+ if (typeof value === 'string') return value;
42
+ if (value == null || typeof value !== 'object') return undefined;
43
+
44
+ const nested = value as Record<string, unknown>;
45
+ return typeof nested['id'] === 'string' ? nested['id'] : undefined;
46
+ }
47
+
48
+ function ok(body: CompleteVisitResponse): FunctionResponse<CompleteVisitResponse> {
49
+ return new FunctionResponse({
50
+ body,
51
+ statusCode: 200,
52
+ headers: {},
53
+ message: body.message,
54
+ });
55
+ }
56
+
57
+ function badRequest(message: string): FunctionResponse<{ error: string }> {
58
+ return new FunctionResponse({
59
+ body: { error: message },
60
+ statusCode: 400,
61
+ headers: {},
62
+ message,
63
+ });
64
+ }
65
+
66
+ export async function onRipplingEvent(
67
+ event: CompleteVisitEvent,
68
+ context: FunctionContext,
69
+ ): Promise<FunctionResponse<CompleteVisitResponse | { error: string }>> {
70
+ if (event.object_api_name !== APPOINTMENT_OBJECT_API_NAME || event.button !== 'dental_complete_visit_fn') {
71
+ return badRequest('Unsupported detail view action.');
72
+ }
73
+
74
+ const client = createClient(context);
75
+ const appointment = await client.customObjects.records.retrieve(
76
+ APPOINTMENT_OBJECT_API_NAME,
77
+ event.record_id,
78
+ );
79
+
80
+ if (stringValue(appointment, 'appointment_status__c') === 'Completed') {
81
+ return ok({
82
+ appointmentId: event.record_id,
83
+ message: `${appointment.name} is already completed.`,
84
+ });
85
+ }
86
+
87
+ await client.customObjects.records.update(APPOINTMENT_OBJECT_API_NAME, event.record_id, {
88
+ appointment_status__c: 'Completed',
89
+ visit_notes__c: stringValue(appointment, 'visit_notes__c'),
90
+ });
91
+
92
+ const nextStepSummary = event.parameters.nextStepSummary?.trim();
93
+ if (!nextStepSummary) {
94
+ return ok({
95
+ appointmentId: event.record_id,
96
+ message: `${appointment.name} marked completed.`,
97
+ });
98
+ }
99
+
100
+ const patientId = lookupId(appointment, 'patient_ref__c');
101
+ if (!patientId) {
102
+ return ok({
103
+ appointmentId: event.record_id,
104
+ message: `${appointment.name} marked completed. No treatment plan was created because the appointment has no patient.`,
105
+ });
106
+ }
107
+
108
+ const treatmentPlan = await client.customObjects.records.create(TREATMENT_PLAN_OBJECT_API_NAME, {
109
+ name: `Follow-up: ${appointment.name}`,
110
+ plan_patient_ref__c: patientId,
111
+ plan_status__c: 'Draft',
112
+ procedures_summary__c: nextStepSummary,
113
+ });
114
+ const response: CompleteVisitResponse = {
115
+ appointmentId: event.record_id,
116
+ message: `${appointment.name} marked completed and follow-up treatment plan drafted.`,
117
+ };
118
+ if (treatmentPlan.data?.id != null) response.treatmentPlanId = treatmentPlan.data.id;
119
+
120
+ return ok(response);
121
+ }
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'dental_operatory__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'dental_patient__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'dental_treatment_plan__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'gym_class_enrollment__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'gym_member__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'gym_class_session__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'gym_trainer__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -1,15 +1,15 @@
1
- import { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
1
+ import { FunctionContext, FunctionResponse, SduiPageFunctionEvent } from '@rippling/rippling-sdk';
2
2
  import { ObjectListView, render } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
3
3
 
4
4
  const OBJECT = 'simple_todo__c';
5
5
 
6
6
  export async function onRipplingEvent(
7
- event: FunctionEvent,
7
+ event: SduiPageFunctionEvent,
8
8
  context: FunctionContext,
9
9
  ): Promise<FunctionResponse> {
10
- const action = event['parameters']?.action;
10
+ const action = event.parameters.action;
11
11
 
12
- if (!action || action === 'init') {
12
+ if (action === 'init') {
13
13
  const spec = render({
14
14
  root: ObjectListView({
15
15
  props: { objectApiName: OBJECT },
@@ -32,10 +32,20 @@ import {
32
32
  setState,
33
33
  triggerFunction,
34
34
  } from '@rippling/pebble-sdui-web/catalogs/custom-apps';
35
- import RipplingSDK, { FunctionContext, FunctionEvent, FunctionResponse } from '@rippling/rippling-sdk';
35
+ import RipplingSDK, {
36
+ FunctionContext,
37
+ FunctionResponse,
38
+ SduiPageFunctionEvent,
39
+ } from '@rippling/rippling-sdk';
36
40
  import type { CustomObjectDataRow } from '@rippling/rippling-sdk/resources/custom-objects/records';
37
41
 
38
42
  const OBJECT_API_NAME = 'todo__c';
43
+ type TodoPageAction = 'init' | 'addTodo' | 'toggleTodo' | 'clearCompleted';
44
+ type TodoPageFunctionParameters = {
45
+ action: TodoPageAction;
46
+ text?: string;
47
+ todoId?: string;
48
+ };
39
49
 
40
50
  type Todo = {
41
51
  id: string;
@@ -125,7 +135,7 @@ function serverError(error: unknown): FunctionResponse {
125
135
  });
126
136
  }
127
137
 
128
- function stringParam(params: Record<string, unknown>, key: string): string {
138
+ function stringParam(params: TodoPageFunctionParameters, key: 'text' | 'todoId'): string {
129
139
  const value = params[key];
130
140
  return typeof value === 'string' ? value.trim() : '';
131
141
  }
@@ -396,7 +406,7 @@ function renderSpec(state: TodoAppState, functionId: string) {
396
406
 
397
407
  async function addTodo(
398
408
  client: RipplingSDK,
399
- params: Record<string, unknown>,
409
+ params: TodoPageFunctionParameters,
400
410
  roleId: string,
401
411
  ): Promise<TodoListState> {
402
412
  const text = stringParam(params, 'text');
@@ -415,7 +425,7 @@ async function addTodo(
415
425
 
416
426
  async function toggleTodo(
417
427
  client: RipplingSDK,
418
- params: Record<string, unknown>,
428
+ params: TodoPageFunctionParameters,
419
429
  roleId: string,
420
430
  ): Promise<TodoListState> {
421
431
  const todoId = stringParam(params, 'todoId');
@@ -449,11 +459,11 @@ async function clearCompleted(client: RipplingSDK, roleId: string): Promise<Todo
449
459
  }
450
460
 
451
461
  export async function onRipplingEvent(
452
- event: FunctionEvent,
462
+ event: SduiPageFunctionEvent<TodoPageFunctionParameters>,
453
463
  context: FunctionContext,
454
464
  ): Promise<FunctionResponse> {
455
- const params = (event['parameters'] ?? {}) as Record<string, unknown>;
456
- const action = typeof params['action'] === 'string' ? params['action'] : 'init';
465
+ const params = event.parameters;
466
+ const action = params.action;
457
467
  const roleId = context.function.role_id;
458
468
  if (!roleId) {
459
469
  return badRequest('Role ID is required');
package/functions.d.mts CHANGED
@@ -11,7 +11,49 @@ export declare class FunctionResponse<T = Record<string, any>> {
11
11
  message: string;
12
12
  constructor({ body, statusCode, headers, message, }?: FunctionResponseOptions<T>);
13
13
  }
14
- export type FunctionEvent = Record<string, any>;
14
+ export type FunctionEventPrimitive = string | number | boolean | null;
15
+ export type FunctionEventValue = FunctionEventPrimitive | FunctionEventValue[] | {
16
+ [key: string]: FunctionEventValue | undefined;
17
+ };
18
+ export type FunctionEventParameters = Record<string, FunctionEventValue | undefined>;
19
+ export type FunctionEventQueryParams = Record<string, string | string[] | undefined>;
20
+ type FunctionEventParameterShape<T> = {
21
+ [K in keyof T]: FunctionEventValue | undefined;
22
+ };
23
+ type FunctionEventQueryParamShape<T> = {
24
+ [K in keyof T]: string | string[] | undefined;
25
+ };
26
+ export interface FunctionEventUrl<TQueryParams extends FunctionEventQueryParamShape<TQueryParams> = FunctionEventQueryParams> {
27
+ path: string;
28
+ queryParams: TQueryParams;
29
+ hash: string;
30
+ }
31
+ export interface SduiPageFunctionParameters extends FunctionEventParameters {
32
+ action: string;
33
+ }
34
+ export interface SduiPageFunctionEvent<TParameters extends {
35
+ action: string;
36
+ } & FunctionEventParameterShape<TParameters> = SduiPageFunctionParameters, TQueryParams extends FunctionEventQueryParamShape<TQueryParams> = FunctionEventQueryParams> {
37
+ url: FunctionEventUrl<TQueryParams>;
38
+ parameters: TParameters;
39
+ }
40
+ export interface DetailViewActionFunctionEvent<TParameters extends FunctionEventParameterShape<TParameters> = FunctionEventParameters, TObjectApiName extends string = string, TButton extends string = string, TLayoutId extends string = string> {
41
+ app_id: string | null;
42
+ button: TButton;
43
+ current_user: string;
44
+ layout_id: TLayoutId;
45
+ object_api_name: TObjectApiName;
46
+ parameters: TParameters;
47
+ record_id: string;
48
+ trigger_type: 'record view';
49
+ url: string;
50
+ }
51
+ export type FunctionEvent = FunctionEventParameters;
52
+ export type FunctionHandler<TEvent = FunctionEvent, TContext extends FunctionContext = FunctionContext> = (event: TEvent, context: TContext) => FunctionResponse | Promise<FunctionResponse>;
53
+ export type SduiPageFunctionHandler<TParameters extends {
54
+ action: string;
55
+ } & FunctionEventParameterShape<TParameters> = SduiPageFunctionParameters, TQueryParams extends FunctionEventQueryParamShape<TQueryParams> = FunctionEventQueryParams> = FunctionHandler<SduiPageFunctionEvent<TParameters, TQueryParams>>;
56
+ export type DetailViewActionFunctionHandler<TParameters extends FunctionEventParameterShape<TParameters> = FunctionEventParameters, TObjectApiName extends string = string, TButton extends string = string, TLayoutId extends string = string> = FunctionHandler<DetailViewActionFunctionEvent<TParameters, TObjectApiName, TButton, TLayoutId>>;
15
57
  export type DurableDuration = number | string;
16
58
  export type DurableTimestamp = number | Date | string;
17
59
  export interface DurableWaitForEventOptions {
@@ -107,4 +149,5 @@ export declare class DataBridgeRateLimitError extends Error {
107
149
  waitTimeInSeconds: number;
108
150
  constructor(message: string, waitTimeInSeconds: number);
109
151
  }
152
+ export {};
110
153
  //# sourceMappingURL=functions.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"functions.d.mts","sourceRoot":"","sources":["src/functions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"functions.d.mts","sourceRoot":"","sources":["src/functions.ts"],"names":[],"mappings":"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"}