@nauticana/sail 1.1.24 → 1.1.26

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.
@@ -8,9 +8,11 @@ export interface RealtimeChannelFrame<T = unknown> {
8
8
  data: T;
9
9
  }
10
10
 
11
+ const CONTROL_OPS = ['subscribed', 'unsubscribed', 'error'] as const;
12
+
11
13
  /** Control frames of the keel realtime wire protocol. */
12
14
  interface ControlFrame {
13
- op: 'subscribed' | 'unsubscribed' | 'error';
15
+ op: typeof CONTROL_OPS[number];
14
16
  channel?: string;
15
17
  reason?: string;
16
18
  }
@@ -93,7 +95,7 @@ export class RealtimeService {
93
95
  if (this.channels.delete(channel) && this.connected()) this.sendFrame({ op: 'unsubscribe', channel });
94
96
  }
95
97
 
96
- /** Payloads keel delivers to this user directly (SendToUser / PublishUser). */
98
+ /** Payloads keel delivers to this user directly (SendToUser / PublishUser), e.g. `{op: 'notification', ...}`. */
97
99
  userFrames<T = unknown>(): Observable<T> {
98
100
  return this.frames$.pipe(filter((f): f is T => !isChannelFrame(f) && !isControlFrame(f)));
99
101
  }
@@ -132,7 +134,7 @@ function isChannelFrame(f: unknown): f is RealtimeChannelFrame {
132
134
  }
133
135
 
134
136
  function isControlFrame(f: unknown): f is ControlFrame {
135
- return !!f && typeof f === 'object' && 'op' in f;
137
+ return !!f && typeof f === 'object' && CONTROL_OPS.includes((f as { op?: unknown }).op as ControlFrame['op']);
136
138
  }
137
139
 
138
140
  /** ws(s):// form of the configured backend host plus `path`; same-origin when no host is set. */
@@ -153,8 +153,18 @@ export class BackendService extends BaseRestService {
153
153
  * the call will POST to {host}{api_prefix}{actionPath} with the
154
154
  * supplied body. For record-specific actions the body carries the
155
155
  * primary key values; for table-level actions it is typically `{}`.
156
+ * A body carrying a File/Blob posts as `multipart/form-data`.
156
157
  */
157
158
  executeAction<T = unknown>(actionPath: string, body: Record<string, unknown> = {}): Observable<T> {
158
- return this.http.post<T>(this.apiUrl(actionPath), body).pipe(catchError((err) => this.handleError(err)));
159
+ return this.http.post<T>(this.apiUrl(actionPath), multipartWhenFile(body)).pipe(catchError((err) => this.handleError(err)));
159
160
  }
160
161
  }
162
+
163
+ function multipartWhenFile(body: Record<string, unknown>): Record<string, unknown> | FormData {
164
+ if (!Object.values(body).some((value) => value instanceof Blob)) return body;
165
+ const form = new FormData();
166
+ for (const [key, value] of Object.entries(body)) {
167
+ if (value != null) form.append(key, value instanceof Blob ? value : String(value));
168
+ }
169
+ return form;
170
+ }
@@ -77,11 +77,14 @@ export const RestURL = {
77
77
  agencyAcceptInviteURL: '/api/v1/agency/invite/accept',
78
78
  agencyDelegationURL: '/api/v1/agency/delegation',
79
79
  agencyRevokeDelegationURL: '/api/v1/agency/delegation/revoke',
80
- // User payment methods — list/delete go through keel's generic REST
81
- // CRUD against the UserSpecific basis table; set-default is a
82
- // TableAction (basis table_action row), mounted at the conventional
83
- // URL POST /api/v1/user_payment_method/set_default.
80
+ // User payment methods — list is keel's generic REST CRUD; set_default and
81
+ // remove are keel UserPaymentMethodHandler table actions.
84
82
  paymentMethodSetDefaultURL: '/api/v1/user_payment_method/set_default',
83
+ paymentMethodRemoveURL: '/api/v1/user_payment_method/remove',
84
+ // Partner documents — keel DocumentHandler, mounted at its TableActionPath shape.
85
+ partnerDocumentUploadURL: '/api/v1/partner_document/upload',
86
+ partnerDocumentPreviewURL: '/api/v1/partner_document/preview',
87
+ partnerDocumentReviewURL: '/api/v1/partner_document/review',
85
88
  };
86
89
 
87
90
  /** Call this at app startup to set the backend host URL */
@@ -8,13 +8,10 @@ import { UserPaymentMethod } from '../model/appdata';
8
8
  /**
9
9
  * UserPaymentMethodService — consumer-side saved-payment-methods API.
10
10
  *
11
- * list and delete go through keel's generic REST CRUD against the
12
- * basis user_payment_method table — that table is UserSpecific (FK
13
- * column `user_id`), so the auto-filter scopes reads + owner-locks
14
- * DELETE without any custom server-side glue. setDefault has a custom
15
- * endpoint because it needs an atomic multi-row UPDATE
16
- * (`SET is_default = (id = ?) WHERE user_id = session`) that abstract
17
- * single-row CRUD can't express.
11
+ * list goes through keel's generic REST CRUD against the UserSpecific basis
12
+ * user_payment_method table. remove and setDefault are keel table actions:
13
+ * remove detaches the method at the provider before deleting the row, so keel
14
+ * grants no generic DELETE on the table.
18
15
  */
19
16
  @Injectable({ providedIn: 'root' })
20
17
  export class UserPaymentMethodService extends BaseRestService {
@@ -29,15 +26,12 @@ export class UserPaymentMethodService extends BaseRestService {
29
26
  return this.backend.list<UserPaymentMethod>('user_payment_method');
30
27
  }
31
28
 
32
- /** Delete a saved payment method. user_id is auto-scoped by keel. */
33
- delete(id: number): Observable<{ message: string }> {
34
- return this.backend.delete('user_payment_method', { Id: String(id) });
29
+ /** Detach a saved payment method at the provider and delete it. */
30
+ remove(id: number): Observable<{ message: string }> {
31
+ return this.http.post<{ message: string }>(this.url(RestURL.paymentMethodRemoveURL), { id });
35
32
  }
36
33
 
37
- /**
38
- * Mark one row as default; clears every other row in the same call.
39
- * Custom endpoint — see service-class doc for the rationale.
40
- */
34
+ /** Mark one row as default; clears every other row in the same call. */
41
35
  setDefault(id: number): Observable<{ message: string }> {
42
36
  return this.http.post<{ message: string }>(this.url(RestURL.paymentMethodSetDefaultURL), { id });
43
37
  }