spaps-sdk 1.10.0 → 1.10.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/index.mjs CHANGED
@@ -637,7 +637,7 @@ var SPAPSClient = class _SPAPSClient {
637
637
  * @param userId - Optional user ID override (secret key contexts only).
638
638
  */
639
639
  check: async (key, userId) => {
640
- const q = new URLSearchParams({ key });
640
+ const q = new URLSearchParams({ entitlement_key: key });
641
641
  if (userId) q.append("user_id", userId);
642
642
  const res = await this.client.get(
643
643
  `/api/entitlements/check?${q.toString()}`,
@@ -651,7 +651,7 @@ var SPAPSClient = class _SPAPSClient {
651
651
  * Note: For publishable key contexts, only `resource_type=user` is permitted.
652
652
  * Non-user resource types will return a 403 error (enforced server-side).
653
653
  *
654
- * @param resourceType - The resource type (e.g. "user", "company", "org", "system").
654
+ * @param resourceType - The resource type (e.g. "user", "company", "org", "system", "project").
655
655
  * @param resourceId - Optional specific resource ID.
656
656
  */
657
657
  listByResource: async (resourceType, resourceId) => {
@@ -722,6 +722,69 @@ var SPAPSClient = class _SPAPSClient {
722
722
  );
723
723
  return this.unwrapApiResponse(res, "Failed to create issue report");
724
724
  },
725
+ /**
726
+ * Upload one private pending screenshot attachment.
727
+ */
728
+ uploadAttachment: async (file, options) => {
729
+ if (typeof FormData === "undefined") {
730
+ throw new Error("FormData is required to upload issue report attachments");
731
+ }
732
+ const formData = new FormData();
733
+ const fileWithOptionalName = file;
734
+ const inferredFilename = typeof fileWithOptionalName.name === "string" ? fileWithOptionalName.name : void 0;
735
+ const filename = options?.filename ?? inferredFilename;
736
+ if (filename) {
737
+ formData.append("file", file, filename);
738
+ } else {
739
+ formData.append("file", file);
740
+ }
741
+ const res = await this.client.post(
742
+ "/api/v1/issue-reports/attachments",
743
+ formData,
744
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
745
+ );
746
+ return this.unwrapApiResponse(res, "Failed to upload issue report attachment");
747
+ },
748
+ /**
749
+ * List non-deleted screenshot attachments for one issue report.
750
+ */
751
+ listAttachments: async (issueReportId) => {
752
+ const res = await this.client.get(
753
+ `/api/v1/issue-reports/${encodeURIComponent(issueReportId)}/attachments`,
754
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
755
+ );
756
+ return this.unwrapApiResponse(res, "Failed to list issue report attachments");
757
+ },
758
+ /**
759
+ * Return a short-lived private attachment access URL.
760
+ */
761
+ getAttachmentAccess: async (attachmentId) => {
762
+ const res = await this.client.get(
763
+ `/api/v1/issue-reports/attachments/${encodeURIComponent(attachmentId)}/access`,
764
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
765
+ );
766
+ return this.unwrapApiResponse(
767
+ res,
768
+ "Failed to get issue report attachment access URL"
769
+ );
770
+ },
771
+ /**
772
+ * Return a short-lived private attachment access URL.
773
+ *
774
+ * @deprecated Use getAttachmentAccess(attachmentId).
775
+ */
776
+ getAttachmentAccessUrl: async (attachmentId) => {
777
+ return this.issueReporting.getAttachmentAccess(attachmentId);
778
+ },
779
+ /**
780
+ * Soft-delete one owned screenshot attachment.
781
+ */
782
+ deleteAttachment: async (attachmentId) => {
783
+ await this.client.delete(
784
+ `/api/v1/issue-reports/attachments/${encodeURIComponent(attachmentId)}`,
785
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
786
+ );
787
+ },
725
788
  /**
726
789
  * Create a short-lived voice transcription token for issue reporting.
727
790
  */
@@ -754,6 +817,82 @@ var SPAPSClient = class _SPAPSClient {
754
817
  this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
755
818
  );
756
819
  return this.unwrapApiResponse(res, "Failed to reply to issue report");
820
+ },
821
+ /**
822
+ * List the chronological, reporter-visible message thread for one owned
823
+ * issue report. Only active, reporter-visible rows are returned; retracted
824
+ * or superseded operator messages are excluded and raw audit payloads are
825
+ * never exposed. `needs_response` badges an open clarification request.
826
+ */
827
+ listMessages: async (issueReportId) => {
828
+ const res = await this.client.get(
829
+ `/api/v1/issue-reports/${issueReportId}/messages`,
830
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
831
+ );
832
+ return this.unwrapApiResponse(res, "Failed to list issue report messages");
833
+ },
834
+ /**
835
+ * Submit a reporter clarification response on one owned issue report. This
836
+ * does NOT reopen a closed case (use `reply` for that). Idempotent on
837
+ * `idempotency_key`: same key + same body returns the existing message,
838
+ * same key + different body returns 409 ISSUE_REPORT_MESSAGE_CONFLICT.
839
+ */
840
+ submitMessage: async (issueReportId, payload) => {
841
+ const res = await this.client.post(
842
+ `/api/v1/issue-reports/${issueReportId}/messages`,
843
+ payload,
844
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
845
+ );
846
+ return this.unwrapApiResponse(res, "Failed to submit issue report message");
847
+ },
848
+ /**
849
+ * Triage-operator message commands. These require a secret key context and a
850
+ * triage role/capability; publishable browser contexts are rejected by the
851
+ * server. Provide the secret key as the SDK's API key.
852
+ */
853
+ triage: {
854
+ /**
855
+ * List all projection rows for an app-scoped report (including corrected
856
+ * rows) for authorized triage operators.
857
+ */
858
+ listMessages: async (issueReportId) => {
859
+ const res = await this.client.get(
860
+ `/api/v1/issue-reports/triage/${issueReportId}/messages`,
861
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
862
+ );
863
+ return this.unwrapApiResponse(
864
+ res,
865
+ "Failed to list triage issue report messages"
866
+ );
867
+ },
868
+ /**
869
+ * Post a clarification_request or final_response reporter-visible message
870
+ * as a triage operator. Idempotent on `idempotency_key`; a key reused with
871
+ * a different body returns 409. A final_response can drive a terminal
872
+ * lifecycle transition via `resolve_case`; the internal resolution_note is
873
+ * never auto-displayed to reporters.
874
+ */
875
+ postMessage: async (issueReportId, payload) => {
876
+ const res = await this.client.post(
877
+ `/api/v1/issue-reports/triage/${issueReportId}/messages`,
878
+ payload,
879
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
880
+ );
881
+ return this.unwrapApiResponse(res, "Failed to post triage issue report message");
882
+ },
883
+ /**
884
+ * Retract an operator-authored message. The body is retained; the row's
885
+ * state is marked `retracted`. Retracting an already-retracted message is
886
+ * a safe no-op.
887
+ */
888
+ retractMessage: async (issueReportId, messageId, payload = {}) => {
889
+ const res = await this.client.post(
890
+ `/api/v1/issue-reports/triage/${issueReportId}/messages/${messageId}/retract`,
891
+ payload,
892
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
893
+ );
894
+ return this.unwrapApiResponse(res, "Failed to retract triage issue report message");
895
+ }
757
896
  }
758
897
  };
759
898
  /**
@@ -771,6 +910,17 @@ var SPAPSClient = class _SPAPSClient {
771
910
  );
772
911
  return this.unwrapApiResponse(res, "Failed to create app link");
773
912
  },
913
+ /**
914
+ * Update a short link owned by the authenticated user.
915
+ */
916
+ update: async (username, slug, payload) => {
917
+ const res = await this.client.patch(
918
+ `/api/v1/app-links/${encodeURIComponent(username)}/${encodeURIComponent(slug)}`,
919
+ payload,
920
+ this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
921
+ );
922
+ return this.unwrapApiResponse(res, "Failed to update app link");
923
+ },
774
924
  /**
775
925
  * Resolve a public short link for the active application.
776
926
  */
@@ -785,6 +935,58 @@ var SPAPSClient = class _SPAPSClient {
785
935
  return this.unwrapApiResponse(res, "Failed to get app link");
786
936
  }
787
937
  };
938
+ /**
939
+ * Marketing events and experiment results.
940
+ *
941
+ * Use a publishable key for browser-side event emission. Use a secret key
942
+ * from a trusted server or agent process when reading experiment results.
943
+ */
944
+ marketing = {
945
+ /**
946
+ * Emit one anonymous attribution touch or experiment exposure.
947
+ */
948
+ emit: async (payload) => {
949
+ if (payload.event_type === "experiment_exposure") {
950
+ if (!payload.experiment_id?.trim()) {
951
+ throw new Error("experiment_id is required for experiment_exposure events");
952
+ }
953
+ const variant = payload.variant_id ?? payload.variant;
954
+ if (!variant?.trim()) {
955
+ throw new Error("variant_id or variant is required for experiment_exposure events");
956
+ }
957
+ }
958
+ const res = await this.client.post("/api/marketing-events/ingest", payload);
959
+ return this.unwrapApiResponse(
960
+ res,
961
+ "Failed to emit marketing event"
962
+ );
963
+ },
964
+ /**
965
+ * Alias for emit(), matching the backend ingest endpoint language.
966
+ */
967
+ ingest: async (payload) => {
968
+ return this.marketing.emit(payload);
969
+ },
970
+ /**
971
+ * Read per-variant experiment results and the conservative stop signal.
972
+ */
973
+ getExperimentResults: async (experimentId) => {
974
+ const encodedExperimentId = encodeURIComponent(experimentId);
975
+ const res = await this.client.get(
976
+ `/api/marketing/experiments/${encodedExperimentId}/results`
977
+ );
978
+ return this.unwrapApiResponse(
979
+ res,
980
+ "Failed to get marketing experiment results"
981
+ );
982
+ },
983
+ /**
984
+ * Short alias for getExperimentResults().
985
+ */
986
+ getResults: async (experimentId) => {
987
+ return this.marketing.getExperimentResults(experimentId);
988
+ }
989
+ };
788
990
  static envVar(name) {
789
991
  if (typeof process !== "undefined" && process.env) {
790
992
  return process.env[name];
@@ -1260,9 +1462,9 @@ var SPAPSClient = class _SPAPSClient {
1260
1462
  const res = await this.client.post("/api/stripe/products/with-price", payload, { headers: { Authorization: `Bearer ${this.accessToken}` } });
1261
1463
  return this.unwrapApiResponse(res, "Failed to create product with price");
1262
1464
  },
1263
- createProductWithPriceSuperAdmin: async (productId, payload) => {
1465
+ createProductWithPriceSuperAdmin: async (applicationId, payload) => {
1264
1466
  if (!this.accessToken) throw new Error("Authentication required. Please authenticate first.");
1265
- const res = await this.client.post(`/api/stripe/products/super-admin/${productId}/with-price`, payload, { headers: { Authorization: `Bearer ${this.accessToken}` } });
1467
+ const res = await this.client.post(`/api/stripe/products/super-admin/${applicationId}/with-price`, payload, { headers: { Authorization: `Bearer ${this.accessToken}` } });
1266
1468
  return this.unwrapApiResponse(res, "Failed to create product with price (super admin)");
1267
1469
  },
1268
1470
  setDefaultPrice: async (productId, payload) => {
@@ -1590,6 +1792,25 @@ var SPAPSClient = class _SPAPSClient {
1590
1792
  * after work completes.
1591
1793
  */
1592
1794
  usage = {
1795
+ /**
1796
+ * List active usage feature definitions for this application.
1797
+ */
1798
+ listFeatures: async () => {
1799
+ const res = await this.client.get("/api/usage/features");
1800
+ return this.unwrapApiResponse(res, "Failed to list usage features");
1801
+ },
1802
+ /**
1803
+ * Fetch current window usage status without creating an authorization.
1804
+ */
1805
+ getStatus: async (query) => {
1806
+ const q = new URLSearchParams();
1807
+ q.set("feature_key", query.feature_key);
1808
+ q.set("resource_type", query.resource_type);
1809
+ if (query.resource_id) q.set("resource_id", query.resource_id);
1810
+ if (query.subject_user_id) q.set("subject_user_id", query.subject_user_id);
1811
+ const res = await this.client.get(`/api/usage/status?${q.toString()}`);
1812
+ return this.unwrapApiResponse(res, "Failed to get usage status");
1813
+ },
1593
1814
  /**
1594
1815
  * Authorize proposed usage before a downstream job, inference, or action runs.
1595
1816
  */
@@ -1603,21 +1824,43 @@ var SPAPSClient = class _SPAPSClient {
1603
1824
  record: async (payload) => {
1604
1825
  const res = await this.client.post("/api/usage/record", payload);
1605
1826
  return this.unwrapApiResponse(res, "Failed to record usage");
1827
+ },
1828
+ /**
1829
+ * List usage events in deterministic newest-first order.
1830
+ */
1831
+ listHistory: async (query = {}) => {
1832
+ const q = new URLSearchParams();
1833
+ if (query.feature_key) q.set("feature_key", query.feature_key);
1834
+ if (query.resource_type) q.set("resource_type", query.resource_type);
1835
+ if (query.resource_id) q.set("resource_id", query.resource_id);
1836
+ if (query.subject_user_id) q.set("subject_user_id", query.subject_user_id);
1837
+ if (query.limit) q.set("limit", String(query.limit));
1838
+ if (typeof query.offset === "number") q.set("offset", String(query.offset));
1839
+ const suffix = q.toString() ? `?${q.toString()}` : "";
1840
+ const res = await this.client.get(`/api/usage/history${suffix}`);
1841
+ return this.unwrapApiResponse(res, "Failed to list usage history");
1606
1842
  }
1607
1843
  };
1608
1844
  // Stripe Methods
1609
1845
  async createCheckoutSession(priceId, successUrl, cancelUrl) {
1610
- return this.client.post("/api/stripe/create-checkout-session", {
1611
- price_id: priceId,
1846
+ return this.client.post("/api/stripe/checkout-sessions", {
1847
+ mode: "payment",
1848
+ line_items: [{ price_id: priceId, quantity: 1 }],
1612
1849
  success_url: successUrl,
1613
- cancel_url: cancelUrl
1850
+ cancel_url: cancelUrl ?? successUrl
1614
1851
  });
1615
1852
  }
1616
- async getSubscription() {
1617
- return this.client.get("/api/stripe/subscription");
1853
+ async getSubscription(subscriptionId) {
1854
+ if (subscriptionId) {
1855
+ return this.client.get(`/api/stripe/subscription/${subscriptionId}`);
1856
+ }
1857
+ return this.client.get("/api/stripe/subscriptions");
1618
1858
  }
1619
- async cancelSubscription() {
1620
- await this.client.delete("/api/stripe/subscription");
1859
+ async cancelSubscription(subscriptionId, options = {}) {
1860
+ if (!subscriptionId) {
1861
+ throw new Error("subscriptionId is required to cancel a subscription.");
1862
+ }
1863
+ return this.client.post(`/api/stripe/subscription/${subscriptionId}/cancel`, options);
1621
1864
  }
1622
1865
  // Usage Methods
1623
1866
  async authorizeUsage(payload) {
@@ -1626,6 +1869,18 @@ var SPAPSClient = class _SPAPSClient {
1626
1869
  async recordUsage(payload) {
1627
1870
  return this.usage.record(payload);
1628
1871
  }
1872
+ async getUsageStatus(query) {
1873
+ return this.usage.getStatus(query);
1874
+ }
1875
+ async listUsageHistory(query = {}) {
1876
+ return this.usage.listHistory(query);
1877
+ }
1878
+ async emitMarketingEvent(payload) {
1879
+ return this.marketing.emit(payload);
1880
+ }
1881
+ async getMarketingExperimentResults(experimentId) {
1882
+ return this.marketing.getExperimentResults(experimentId);
1883
+ }
1629
1884
  // Secure Messaging Methods
1630
1885
  async createSecureMessage(payload) {
1631
1886
  const response = await this.client.post("/api/secure-messages", payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spaps-sdk",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "Sweet Potato Authentication & Payment Service SDK - Zero-config client with built-in permission checking, role-based access control, and dayrate scheduling",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -51,7 +51,7 @@
51
51
  "dependencies": {
52
52
  "axios": "^1.15.1",
53
53
  "cross-fetch": "^4.0.0",
54
- "spaps-types": "^1.3.0"
54
+ "spaps-types": "^1.4.2"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/node": "^20.10.0",
@@ -81,4 +81,4 @@
81
81
  "engines": {
82
82
  "node": ">=14.0.0"
83
83
  }
84
- }
84
+ }