@proveanything/smartlinks 1.2.3 → 1.3.1

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/http.js CHANGED
@@ -2,6 +2,18 @@
2
2
  // This module replaces the ApiClient constructor. It keeps baseURL, apiKey, bearerToken
3
3
  // in module-scope variables, and provides a shared `request<T>(path)` helper that will
4
4
  // be used by all namespaced files (collection.ts, product.ts, etc.).
5
+ var __rest = (this && this.__rest) || function (s, e) {
6
+ var t = {};
7
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
8
+ t[p] = s[p];
9
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
10
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
11
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
12
+ t[p[i]] = s[p[i]];
13
+ }
14
+ return t;
15
+ };
16
+ import { SmartlinksApiError } from "./types/error";
5
17
  let baseURL = null;
6
18
  let apiKey = undefined;
7
19
  let bearerToken = undefined;
@@ -63,6 +75,88 @@ function safeBodyPreview(body) {
63
75
  }
64
76
  return body;
65
77
  }
78
+ /**
79
+ * Normalizes various server error response formats into a consistent ErrorResponse shape.
80
+ * Handles multiple formats:
81
+ * - { code: number, message: string } (standard)
82
+ * - { errorCode: string, errorText: string }
83
+ * - { error: string, message: string }
84
+ * - { error: string } (just error field)
85
+ * - { ok: false, error: string }
86
+ * - Plain string
87
+ *
88
+ * @param responseBody - The parsed JSON response body from the server
89
+ * @param statusCode - HTTP status code
90
+ * @returns Normalized ErrorResponse object
91
+ */
92
+ function normalizeErrorResponse(responseBody, statusCode) {
93
+ if (!responseBody || typeof responseBody !== 'object') {
94
+ // Plain string or non-object response
95
+ const message = typeof responseBody === 'string' ? responseBody : 'Request failed';
96
+ return {
97
+ code: statusCode,
98
+ message,
99
+ };
100
+ }
101
+ // Extract all possible fields from the response
102
+ const { code, errorCode, error, message, errorText, ok } = responseBody, rest = __rest(responseBody
103
+ // Determine the error code (prefer numeric code, fall back to errorCode or error string)
104
+ , ["code", "errorCode", "error", "message", "errorText", "ok"]);
105
+ // Determine the error code (prefer numeric code, fall back to errorCode or error string)
106
+ let normalizedCode = statusCode;
107
+ if (typeof code === 'number') {
108
+ normalizedCode = code;
109
+ }
110
+ else if (typeof errorCode === 'string' || typeof error === 'string') {
111
+ // Keep statusCode as numeric code, but preserve the string code in details
112
+ }
113
+ // Determine the error message
114
+ let normalizedMessage;
115
+ if (message) {
116
+ normalizedMessage = String(message);
117
+ }
118
+ else if (errorText) {
119
+ normalizedMessage = String(errorText);
120
+ }
121
+ else if (error) {
122
+ normalizedMessage = String(error);
123
+ }
124
+ else if (ok === false) {
125
+ normalizedMessage = 'Request failed';
126
+ }
127
+ else {
128
+ normalizedMessage = `Request failed with status ${statusCode}`;
129
+ }
130
+ // Extract the server-specific error code string (distinct from HTTP status code)
131
+ let normalizedErrorCode;
132
+ if (errorCode && typeof errorCode === 'string') {
133
+ normalizedErrorCode = errorCode;
134
+ }
135
+ else if (error && typeof error === 'string') {
136
+ normalizedErrorCode = error;
137
+ }
138
+ // Collect any additional details
139
+ const details = Object.assign({}, rest);
140
+ // Preserve error fields in details for backward compatibility
141
+ if (errorCode && typeof errorCode === 'string') {
142
+ details.errorCode = errorCode;
143
+ }
144
+ if (error && typeof error === 'string') {
145
+ details.error = error;
146
+ }
147
+ if (errorText && errorText !== normalizedMessage) {
148
+ details.errorText = errorText;
149
+ }
150
+ if (ok === false) {
151
+ details.ok = ok;
152
+ }
153
+ return {
154
+ code: normalizedCode,
155
+ errorCode: normalizedErrorCode,
156
+ message: normalizedMessage,
157
+ details: Object.keys(details).length > 0 ? details : undefined,
158
+ };
159
+ }
66
160
  /**
67
161
  * Call this once (e.g. at app startup) to configure baseURL/auth.
68
162
  *
@@ -336,14 +430,18 @@ export async function request(path) {
336
430
  });
337
431
  logDebug('[smartlinks] GET response', { url, status: response.status, ok: response.ok });
338
432
  if (!response.ok) {
339
- // Try to parse ErrorResponse; if that fails, throw generic
433
+ // Try to parse error response body and normalize it
434
+ let responseBody;
340
435
  try {
341
- const errBody = (await response.json());
342
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
436
+ responseBody = await response.json();
343
437
  }
344
438
  catch (_a) {
345
- throw new Error(`Request to ${url} failed with status ${response.status}`);
439
+ // Failed to parse JSON, use status code only
440
+ responseBody = null;
346
441
  }
442
+ const errBody = normalizeErrorResponse(responseBody, response.status);
443
+ const message = `Error ${errBody.code}: ${errBody.message}`;
444
+ throw new SmartlinksApiError(message, response.status, errBody, url);
347
445
  }
348
446
  return (await response.json());
349
447
  }
@@ -384,13 +482,16 @@ export async function post(path, body, extraHeaders) {
384
482
  });
385
483
  logDebug('[smartlinks] POST response', { url, status: response.status, ok: response.ok });
386
484
  if (!response.ok) {
485
+ let responseBody;
387
486
  try {
388
- const errBody = (await response.json());
389
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
487
+ responseBody = await response.json();
390
488
  }
391
489
  catch (_a) {
392
- throw new Error(`Request to ${url} failed with status ${response.status}`);
490
+ responseBody = null;
393
491
  }
492
+ const errBody = normalizeErrorResponse(responseBody, response.status);
493
+ const message = `Error ${errBody.code}: ${errBody.message}`;
494
+ throw new SmartlinksApiError(message, response.status, errBody, url);
394
495
  }
395
496
  return (await response.json());
396
497
  }
@@ -431,13 +532,16 @@ export async function put(path, body, extraHeaders) {
431
532
  });
432
533
  logDebug('[smartlinks] PUT response', { url, status: response.status, ok: response.ok });
433
534
  if (!response.ok) {
535
+ let responseBody;
434
536
  try {
435
- const errBody = (await response.json());
436
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
537
+ responseBody = await response.json();
437
538
  }
438
539
  catch (_a) {
439
- throw new Error(`Request to ${url} failed with status ${response.status}`);
540
+ responseBody = null;
440
541
  }
542
+ const errBody = normalizeErrorResponse(responseBody, response.status);
543
+ const message = `Error ${errBody.code}: ${errBody.message}`;
544
+ throw new SmartlinksApiError(message, response.status, errBody, url);
441
545
  }
442
546
  return (await response.json());
443
547
  }
@@ -478,13 +582,16 @@ export async function patch(path, body, extraHeaders) {
478
582
  });
479
583
  logDebug('[smartlinks] PATCH response', { url, status: response.status, ok: response.ok });
480
584
  if (!response.ok) {
585
+ let responseBody;
481
586
  try {
482
- const errBody = (await response.json());
483
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
587
+ responseBody = await response.json();
484
588
  }
485
589
  catch (_a) {
486
- throw new Error(`Request to ${url} failed with status ${response.status}`);
590
+ responseBody = null;
487
591
  }
592
+ const errBody = normalizeErrorResponse(responseBody, response.status);
593
+ const message = `Error ${errBody.code}: ${errBody.message}`;
594
+ throw new SmartlinksApiError(message, response.status, errBody, url);
488
595
  }
489
596
  return (await response.json());
490
597
  }
@@ -528,13 +635,16 @@ export async function requestWithOptions(path, options) {
528
635
  const response = await fetch(url, Object.assign(Object.assign({}, options), { headers }));
529
636
  logDebug('[smartlinks] requestWithOptions response', { url, status: response.status, ok: response.ok });
530
637
  if (!response.ok) {
638
+ let responseBody;
531
639
  try {
532
- const errBody = (await response.json());
533
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
640
+ responseBody = await response.json();
534
641
  }
535
642
  catch (_a) {
536
- throw new Error(`Request to ${url} failed with status ${response.status}`);
643
+ responseBody = null;
537
644
  }
645
+ const errBody = normalizeErrorResponse(responseBody, response.status);
646
+ const message = `Error ${errBody.code}: ${errBody.message}`;
647
+ throw new SmartlinksApiError(message, response.status, errBody, url);
538
648
  }
539
649
  return (await response.json());
540
650
  }
@@ -569,13 +679,16 @@ export async function del(path, extraHeaders) {
569
679
  });
570
680
  logDebug('[smartlinks] DELETE response', { url, status: response.status, ok: response.ok });
571
681
  if (!response.ok) {
682
+ let responseBody;
572
683
  try {
573
- const errBody = (await response.json());
574
- throw new Error(`Error ${errBody.code}: ${errBody.message}`);
684
+ responseBody = await response.json();
575
685
  }
576
686
  catch (_a) {
577
- throw new Error(`Request to ${url} failed with status ${response.status}`);
687
+ responseBody = null;
578
688
  }
689
+ const errBody = normalizeErrorResponse(responseBody, response.status);
690
+ const message = `Error ${errBody.code}: ${errBody.message}`;
691
+ throw new SmartlinksApiError(message, response.status, errBody, url);
579
692
  }
580
693
  // If the response is empty, just return undefined
581
694
  if (response.status === 204)
@@ -85,6 +85,8 @@ export interface UploadAssetOptions {
85
85
  onProgress?: (percent: number) => void;
86
86
  /** Optional: App ID for scoping to a specific microapp */
87
87
  appId?: string;
88
+ /** Optional: Upload via admin route instead of public */
89
+ admin?: boolean;
88
90
  }
89
91
  export interface ListAssetsOptions {
90
92
  scope: {
@@ -1,9 +1,75 @@
1
1
  /**
2
- * Represents a standardized error response.
2
+ * Represents a standardized error response from the server.
3
3
  */
4
4
  export interface ErrorResponse {
5
- /** Numeric error code */
5
+ /** Numeric error code (typically the HTTP status code: 400, 401, 500, etc.) */
6
6
  code: number;
7
- /** Human-readable error message */
7
+ /** Server-specific error code string (e.g., "NOT_AUTHORIZED", "broadcasts.topic.invalid") */
8
+ errorCode?: string;
9
+ /** Human-readable error message in English (should be translated/customized by the application) */
8
10
  message: string;
11
+ /** Additional error details from the server (optional) */
12
+ details?: Record<string, any>;
13
+ }
14
+ /**
15
+ * SDK error class that preserves all error context from HTTP responses.
16
+ * Provides programmatic access to status codes, error codes, and response details.
17
+ *
18
+ * Important: Server-defined string error codes (e.g., "NOT_AUTHORIZED", "broadcasts.topic.invalid")
19
+ * are preserved in the `details` property, not in the numeric `code` property.
20
+ */
21
+ export declare class SmartlinksApiError extends Error {
22
+ readonly statusCode: number;
23
+ readonly errorResponse?: ErrorResponse | undefined;
24
+ readonly url?: string | undefined;
25
+ /**
26
+ * @param message - Human-readable error message (English text from server)
27
+ * @param statusCode - HTTP status code (e.g., 400, 401, 500)
28
+ * @param errorResponse - Parsed error response from the server (if available)
29
+ * @param url - The URL that was requested
30
+ */
31
+ constructor(message: string, statusCode: number, errorResponse?: ErrorResponse | undefined, url?: string | undefined);
32
+ /**
33
+ * Returns the numeric error code from the server response, if available.
34
+ * This is typically the HTTP status code (400, 401, 500, etc.).
35
+ *
36
+ * For server-defined string error codes like "NOT_AUTHORIZED" or "broadcasts.topic.invalid",
37
+ * use: `error.details?.errorCode || error.details?.error`
38
+ */
39
+ get code(): number | undefined;
40
+ /**
41
+ * Returns the server-specific error code string.
42
+ * This is distinct from the HTTP status code (e.g., "NOT_AUTHORIZED", "broadcasts.topic.invalid").
43
+ * This is the primary identifier to check for programmatic error handling.
44
+ */
45
+ get errorCode(): string | undefined;
46
+ /**
47
+ * Returns additional error details from the server, if available.
48
+ * This object contains various server-specific fields that may vary by endpoint.
49
+ */
50
+ get details(): Record<string, any> | undefined;
51
+ /**
52
+ * Check if this is a client error (4xx status code).
53
+ */
54
+ isClientError(): boolean;
55
+ /**
56
+ * Check if this is a server error (5xx status code).
57
+ */
58
+ isServerError(): boolean;
59
+ /**
60
+ * Check if this is an authentication error (401 or 403).
61
+ */
62
+ isAuthError(): boolean;
63
+ /**
64
+ * Check if this is a not found error (404).
65
+ */
66
+ isNotFound(): boolean;
67
+ /**
68
+ * Check if this is a rate limit error (429).
69
+ */
70
+ isRateLimited(): boolean;
71
+ /**
72
+ * Returns a JSON representation of the error for logging/debugging.
73
+ */
74
+ toJSON(): Record<string, any>;
9
75
  }
@@ -1 +1,98 @@
1
- export {};
1
+ /**
2
+ * SDK error class that preserves all error context from HTTP responses.
3
+ * Provides programmatic access to status codes, error codes, and response details.
4
+ *
5
+ * Important: Server-defined string error codes (e.g., "NOT_AUTHORIZED", "broadcasts.topic.invalid")
6
+ * are preserved in the `details` property, not in the numeric `code` property.
7
+ */
8
+ export class SmartlinksApiError extends Error {
9
+ /**
10
+ * @param message - Human-readable error message (English text from server)
11
+ * @param statusCode - HTTP status code (e.g., 400, 401, 500)
12
+ * @param errorResponse - Parsed error response from the server (if available)
13
+ * @param url - The URL that was requested
14
+ */
15
+ constructor(message, statusCode, errorResponse, url) {
16
+ super(message);
17
+ this.statusCode = statusCode;
18
+ this.errorResponse = errorResponse;
19
+ this.url = url;
20
+ this.name = 'SmartlinksApiError';
21
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
22
+ if (Error.captureStackTrace) {
23
+ Error.captureStackTrace(this, SmartlinksApiError);
24
+ }
25
+ }
26
+ /**
27
+ * Returns the numeric error code from the server response, if available.
28
+ * This is typically the HTTP status code (400, 401, 500, etc.).
29
+ *
30
+ * For server-defined string error codes like "NOT_AUTHORIZED" or "broadcasts.topic.invalid",
31
+ * use: `error.details?.errorCode || error.details?.error`
32
+ */
33
+ get code() {
34
+ var _a;
35
+ return (_a = this.errorResponse) === null || _a === void 0 ? void 0 : _a.code;
36
+ }
37
+ /**
38
+ * Returns the server-specific error code string.
39
+ * This is distinct from the HTTP status code (e.g., "NOT_AUTHORIZED", "broadcasts.topic.invalid").
40
+ * This is the primary identifier to check for programmatic error handling.
41
+ */
42
+ get errorCode() {
43
+ var _a;
44
+ return (_a = this.errorResponse) === null || _a === void 0 ? void 0 : _a.errorCode;
45
+ }
46
+ /**
47
+ * Returns additional error details from the server, if available.
48
+ * This object contains various server-specific fields that may vary by endpoint.
49
+ */
50
+ get details() {
51
+ var _a;
52
+ return (_a = this.errorResponse) === null || _a === void 0 ? void 0 : _a.details;
53
+ }
54
+ /**
55
+ * Check if this is a client error (4xx status code).
56
+ */
57
+ isClientError() {
58
+ return this.statusCode >= 400 && this.statusCode < 500;
59
+ }
60
+ /**
61
+ * Check if this is a server error (5xx status code).
62
+ */
63
+ isServerError() {
64
+ return this.statusCode >= 500 && this.statusCode < 600;
65
+ }
66
+ /**
67
+ * Check if this is an authentication error (401 or 403).
68
+ */
69
+ isAuthError() {
70
+ return this.statusCode === 401 || this.statusCode === 403;
71
+ }
72
+ /**
73
+ * Check if this is a not found error (404).
74
+ */
75
+ isNotFound() {
76
+ return this.statusCode === 404;
77
+ }
78
+ /**
79
+ * Check if this is a rate limit error (429).
80
+ */
81
+ isRateLimited() {
82
+ return this.statusCode === 429;
83
+ }
84
+ /**
85
+ * Returns a JSON representation of the error for logging/debugging.
86
+ */
87
+ toJSON() {
88
+ return {
89
+ name: this.name,
90
+ message: this.message,
91
+ statusCode: this.statusCode,
92
+ code: this.code,
93
+ errorCode: this.errorCode,
94
+ details: this.details,
95
+ url: this.url,
96
+ };
97
+ }
98
+ }
@@ -21,3 +21,4 @@ export * from "./template";
21
21
  export * from "./interaction";
22
22
  export * from "./location";
23
23
  export * from "./jobs";
24
+ export * from "./realtime";
@@ -23,3 +23,4 @@ export * from "./template";
23
23
  export * from "./interaction";
24
24
  export * from "./location";
25
25
  export * from "./jobs";
26
+ export * from "./realtime";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Request parameters for obtaining a realtime token.
3
+ */
4
+ export interface RealtimeTokenRequest {
5
+ /** Required - the collection scope */
6
+ collectionId: string;
7
+ /** Optional - scope to specific app */
8
+ appId?: string;
9
+ }
10
+ /**
11
+ * Ably token request response for real-time communications.
12
+ * This token can be used to initialize an Ably client with appropriate permissions.
13
+ */
14
+ export interface AblyTokenRequest {
15
+ /** Ably key name */
16
+ keyName: string;
17
+ /** Token time-to-live in milliseconds */
18
+ ttl: number;
19
+ /** Request timestamp */
20
+ timestamp: number;
21
+ /** JSON string of channel permissions */
22
+ capability: string;
23
+ /** Random nonce */
24
+ nonce: string;
25
+ /** Message authentication code */
26
+ mac: string;
27
+ /** Client identifier: "collectionId:userId:appId?" */
28
+ clientId: string;
29
+ }
30
+ /**
31
+ * Channel patterns for real-time communications:
32
+ *
33
+ * With appId: collection:{collectionId}:app:{appId}:*
34
+ * Examples:
35
+ * - collection:abc:app:xyz:chat:room-1
36
+ * - collection:abc:app:xyz:notifications:alerts
37
+ * - collection:abc:app:xyz:users:online
38
+ *
39
+ * Without appId: collection:{collectionId}:*
40
+ * Examples:
41
+ * - collection:abc:events:updates
42
+ * - collection:abc:users:active
43
+ */
44
+ export type RealtimeChannelPattern = string;
@@ -0,0 +1,2 @@
1
+ // src/types/realtime.ts
2
+ export {};
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.2.3",
3
+ "version": "1.3.1",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
8
  "dist/",
9
- "README.md",
10
- "API_SUMMARY.md"
9
+ "README.md"
11
10
  ],
12
11
  "scripts": {
13
- "build": "tsc",
12
+ "build": "tsc && node scripts/copy-docs-to-dist.js",
14
13
  "docs": "typedoc",
15
14
  "docs:summary": "node generate-api-summary.js",
16
15
  "build:docs": "tsc build-docs.ts --outDir dist && node dist/build-docs.js",
@@ -1,32 +0,0 @@
1
- import type { ActionQueryByUser, ActionCountsQuery, ActorIdsByActionQuery, AppendActionBody, OutcomeCount, ActorId, ActorWithOutcome, ActionEventRow, AdminByUserRequest, AdminCountsByOutcomeRequest, AdminActorIdsByActionRequest, PublicCountsByOutcomeRequest, PublicByUserRequest, CreateActionBody, UpdateActionBody, ListActionsQuery, ActionRecord, ActionList } from "../types/actions";
2
- export declare namespace actions {
3
- /**
4
- * POST /admin/collection/:collectionId/actions/by-user
5
- * Returns BigQuery action rows, newest first.
6
- */
7
- function byUser(collectionId: string, query?: AdminByUserRequest | ActionQueryByUser): Promise<ActionEventRow[]>;
8
- /**
9
- * POST /admin/collection/:collectionId/actions/counts-by-outcome
10
- * Returns array of { outcome, count }.
11
- */
12
- function countsByOutcome(collectionId: string, query?: AdminCountsByOutcomeRequest | ActionCountsQuery): Promise<OutcomeCount[]>;
13
- /**
14
- * POST /admin/collection/:collectionId/actions/actor-ids/by-action
15
- * Returns list of IDs, optionally with outcome when includeOutcome=true.
16
- */
17
- function actorIdsByAction(collectionId: string, query: AdminActorIdsByActionRequest | ActorIdsByActionQuery): Promise<ActorId[] | ActorWithOutcome[]>;
18
- /**
19
- * POST /admin/collection/:collectionId/actions/append
20
- * Appends one action event.
21
- */
22
- function append(collectionId: string, body: AppendActionBody): Promise<{
23
- success: true;
24
- }>;
25
- function create(collectionId: string, body: CreateActionBody): Promise<ActionRecord>;
26
- function list(collectionId: string, query?: ListActionsQuery): Promise<ActionList>;
27
- function get(collectionId: string, id: string): Promise<ActionRecord>;
28
- function update(collectionId: string, id: string, patchBody: UpdateActionBody): Promise<ActionRecord>;
29
- function remove(collectionId: string, id: string): Promise<void>;
30
- function publicCountsByOutcome(collectionId: string, body: PublicCountsByOutcomeRequest, authToken?: string): Promise<OutcomeCount[]>;
31
- function publicMyActions(collectionId: string, body: PublicByUserRequest, authToken?: string): Promise<ActionEventRow[]>;
32
- }
@@ -1,99 +0,0 @@
1
- // src/api/actions.ts
2
- import { request, post, patch, del } from "../http";
3
- function encodeQuery(params) {
4
- const search = new URLSearchParams();
5
- for (const [key, value] of Object.entries(params)) {
6
- if (value === undefined || value === null || value === "")
7
- continue;
8
- if (typeof value === "boolean") {
9
- search.set(key, value ? "true" : "false");
10
- }
11
- else {
12
- search.set(key, String(value));
13
- }
14
- }
15
- const qs = search.toString();
16
- return qs ? `?${qs}` : "";
17
- }
18
- export var actions;
19
- (function (actions) {
20
- /**
21
- * POST /admin/collection/:collectionId/actions/by-user
22
- * Returns BigQuery action rows, newest first.
23
- */
24
- async function byUser(collectionId, query = {}) {
25
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/by-user`;
26
- return post(path, query);
27
- }
28
- actions.byUser = byUser;
29
- /**
30
- * POST /admin/collection/:collectionId/actions/counts-by-outcome
31
- * Returns array of { outcome, count }.
32
- */
33
- async function countsByOutcome(collectionId, query = {}) {
34
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/counts-by-outcome`;
35
- return post(path, query);
36
- }
37
- actions.countsByOutcome = countsByOutcome;
38
- /**
39
- * POST /admin/collection/:collectionId/actions/actor-ids/by-action
40
- * Returns list of IDs, optionally with outcome when includeOutcome=true.
41
- */
42
- async function actorIdsByAction(collectionId, query) {
43
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/actor-ids/by-action`;
44
- return post(path, query);
45
- }
46
- actions.actorIdsByAction = actorIdsByAction;
47
- /**
48
- * POST /admin/collection/:collectionId/actions/append
49
- * Appends one action event.
50
- */
51
- async function append(collectionId, body) {
52
- if (!body.userId && !body.contactId) {
53
- throw new Error("AppendActionBody must include one of userId or contactId");
54
- }
55
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/append`;
56
- return post(path, body);
57
- }
58
- actions.append = append;
59
- // CRUD: Actions (Postgres)
60
- async function create(collectionId, body) {
61
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/`;
62
- return post(path, body);
63
- }
64
- actions.create = create;
65
- async function list(collectionId, query = {}) {
66
- const qs = encodeQuery(query);
67
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/${qs}`;
68
- return request(path);
69
- }
70
- actions.list = list;
71
- async function get(collectionId, id) {
72
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/${encodeURIComponent(id)}`;
73
- return request(path);
74
- }
75
- actions.get = get;
76
- async function update(collectionId, id, patchBody) {
77
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/${encodeURIComponent(id)}`;
78
- return patch(path, patchBody);
79
- }
80
- actions.update = update;
81
- async function remove(collectionId, id) {
82
- const path = `/admin/collection/${encodeURIComponent(collectionId)}/actions/${encodeURIComponent(id)}`;
83
- return del(path);
84
- }
85
- actions.remove = remove;
86
- // Public endpoints (permission-aware)
87
- async function publicCountsByOutcome(collectionId, body, authToken) {
88
- const path = `/public/collection/${encodeURIComponent(collectionId)}/actions/counts-by-outcome`;
89
- const headers = authToken ? { AUTHORIZATION: `Bearer ${authToken}` } : undefined;
90
- return post(path, body, headers);
91
- }
92
- actions.publicCountsByOutcome = publicCountsByOutcome;
93
- async function publicMyActions(collectionId, body, authToken) {
94
- const path = `/public/collection/${encodeURIComponent(collectionId)}/actions/by-user`;
95
- const headers = authToken ? { AUTHORIZATION: `Bearer ${authToken}` } : undefined;
96
- return post(path, body, headers);
97
- }
98
- actions.publicMyActions = publicMyActions;
99
- })(actions || (actions = {}));