@coasy/piece-coasy 0.2.3 → 0.2.5

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/CLAUDE.md ADDED
@@ -0,0 +1,40 @@
1
+ # Coasy Piece — Internal Notes for Claude
2
+
3
+ ## API Reference
4
+
5
+ The action endpoints used by this piece are documented in the private `coasy/coasy-core` repo:
6
+
7
+ https://github.com/coasy/coasy-core/blob/master/docs/apis/backend-api/apps-actions-handler.md
8
+
9
+ The doc is **private** — fetch it with `gh api repos/coasy/coasy-core/contents/docs/apis/backend-api/apps-actions-handler.md --jq '.content' | base64 -d`, not via WebFetch.
10
+
11
+ ### Conventions shared by every action
12
+
13
+ - **Auth:** API key via `ApiKeyHelper.extractApiKey()`. The `appId` is resolved from the key — never pass `appId` in the body.
14
+ - **Base path:** `POST /apps/actions/<actionName>`
15
+ - **Validation:** Server-side via `class-validator`. Bad bodies return `400` with field details.
16
+ - **Response shape:** `{ "message": "...", "<entity>": { ... } }`
17
+
18
+ ### Available actions (as of 2026-05-06)
19
+
20
+ | Action | Endpoint | Purpose |
21
+ | --- | --- | --- |
22
+ | `addTrialPeriod` | `POST /apps/actions/addTrialPeriod` | Grant a trial period to a user on an offer |
23
+ | `assignToUser` | `POST /apps/actions/assignToUser` | Append features / community topics / topic groups / meditation categories to a user |
24
+ | `createEventParticipant` | `POST /apps/actions/createEventParticipant` | Create a participant on an event (free or paid) |
25
+ | `createFunnelParticipant` | `POST /apps/actions/createFunnelParticipant` | Create a funnel participant for lead tracking |
26
+ | `createVoucher` | `POST /apps/actions/createVoucher` | Create a discount voucher tied to offers |
27
+ | `enrollUserCourse` | `POST /apps/actions/enrollUserCourse` | Enroll a user in a course |
28
+ | `findEvent` | `POST /apps/actions/findEvent` | Find events of the calling app by exact title |
29
+ | `sendPushNotification` | `POST /apps/actions/sendPushNotification` | Send a push notification to all of a user's devices |
30
+
31
+ ### Gotchas worth remembering
32
+
33
+ - **`assignToUser`** requires at least one of `features` / `communityTopics` / `communityTopicGroups` / `meditationCategories`; otherwise the server returns `400`. Cross-app `userId` returns `401`, not `404`.
34
+ - **`sendPushNotification`** accepts a `topic` field in the DTO but it is silently discarded by the current `buildNotification` implementation — do not expose it as a piece property until the upstream handler is fixed.
35
+ - **`createFunnelParticipant`** lowercases `email` server-side. The response includes server-generated `funnelParticipantId`, `registrationTime`, and `timestamp`.
36
+ - **`createVoucher`** auto-generates the voucher ID (`VOC-…`) and sets `status: "ACTIVE"`. Setting `countLeft` implicitly sets `isCountLimited: true`.
37
+ - **`addTrialPeriod`** has its own domain error model (`AppSubscriptionError`) mapped to HTTP via `toApiErrorIfAppSubscriptionError` — surface the server's error message rather than masking it.
38
+ - **`addTrialPeriod` funnel guard** (coasy-core PR #220): the piece's `funnelGuard` array maps to the nested body `guards: { funnel: string[] }`. Guards are checked before the user is resolved; a match is a **silent no-op success** (`subscriptionStatus: "BLOCKED"`, `blockedBy` set, HTTP 200) — nothing is created/extended. Omitting it preserves original behavior.
39
+
40
+ When the upstream doc changes, refresh this file by re-fetching the source via `gh api`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coasy/piece-coasy",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "dependencies": {
5
5
  "@sinclair/typebox": "0.34.11",
6
6
  "axios": "1.8.3",
package/src/index.js CHANGED
@@ -23,6 +23,7 @@ const new_subscription_1 = require("./lib/triggers/new-subscription");
23
23
  const new_webinar_participant_1 = require("./lib/triggers/new-webinar-participant");
24
24
  const webinar_participant_attend_1 = require("./lib/triggers/webinar-participant-attend");
25
25
  const webinar_participant_reminder_1 = require("./lib/triggers/webinar-participant-reminder");
26
+ const add_trial_period_1 = require("./lib/actions/add-trial-period");
26
27
  const assign_to_user_1 = require("./lib/actions/assign-to-user");
27
28
  exports.coasyAuth = pieces_framework_1.PieceAuth.CustomAuth({
28
29
  required: true,
@@ -49,6 +50,7 @@ exports.coasy = (0, pieces_framework_1.createPiece)({
49
50
  logoUrl: 'https://console.coasy.io/favicon/apple-icon.png',
50
51
  authors: ['christian-schab'],
51
52
  actions: [
53
+ add_trial_period_1.addTrialPeriod,
52
54
  assign_to_user_1.assignToUser,
53
55
  create_event_participant_1.createEventParticipant,
54
56
  create_funnel_participant_1.createFunnelParticipant,
package/src/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/community/coasy/src/index.ts"],"names":[],"mappings":";;;AAAA,qEAIwC;AACxC,qFAAgF;AAChF,uFAAkF;AAClF,iEAA6D;AAC7D,yEAAoE;AACpE,yDAAqD;AACrD,iFAA4E;AAC5E,8EAA0E;AAC1E,oEAAgE;AAChE,8EAAyE;AACzE,kFAA8E;AAC9E,kFAA8E;AAC9E,kEAA6D;AAC7D,8DAA0D;AAC1D,kFAA6E;AAC7E,kEAA8D;AAC9D,wDAAoD;AACpD,kEAA6D;AAC7D,sEAAkE;AAClE,oFAA+E;AAC/E,0FAAqF;AACrF,8FAAyF;AACzF,iEAA4D;AAE/C,QAAA,SAAS,GAAG,4BAAS,CAAC,UAAU,CAAC;IAC5C,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,oCAAoC;IACjD,KAAK,EAAE;QACL,OAAO,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC1B,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,oBAAoB;YACjC,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,mCAAmC;SAClD,CAAC;QACF,MAAM,EAAE,4BAAS,CAAC,UAAU,CAAC;YAC3B,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,mBAAmB;YAChC,QAAQ,EAAE,IAAI;SACf,CAAC;KACH;CACF,CAAC,CAAC;AAEU,QAAA,KAAK,GAAG,IAAA,8BAAW,EAAC;IAC/B,WAAW,EAAE,OAAO;IACpB,IAAI,EAAE,iBAAS;IACf,WAAW,EAAE,wBAAwB;IACrC,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,iDAAiD;IAC1D,OAAO,EAAE,CAAC,iBAAiB,CAAC;IAC5B,OAAO,EAAE;QACP,6BAAY;QACZ,iDAAsB;QACtB,mDAAuB;QACvB,8BAAa;QACb,qCAAgB;QAChB,sBAAS;QACT,6CAAoB;KACrB;IACD,QAAQ,EAAE;QACR,0CAAmB;QACnB,gCAAc;QACd,yCAAkB;QAClB,8CAAqB;QACrB,8CAAqB;QACrB,6BAAY;QACZ,0BAAW;QACX,6CAAoB;QACpB,8BAAa;QACb,oBAAQ;QACR,6BAAY;QACZ,kCAAe;QACf,+CAAqB;QACrB,qDAAwB;QACxB,yDAA0B;KAC3B;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/pieces/community/coasy/src/index.ts"],"names":[],"mappings":";;;AAAA,qEAIwC;AACxC,qFAAgF;AAChF,uFAAkF;AAClF,iEAA6D;AAC7D,yEAAoE;AACpE,yDAAqD;AACrD,iFAA4E;AAC5E,8EAA0E;AAC1E,oEAAgE;AAChE,8EAAyE;AACzE,kFAA8E;AAC9E,kFAA8E;AAC9E,kEAA6D;AAC7D,8DAA0D;AAC1D,kFAA6E;AAC7E,kEAA8D;AAC9D,wDAAoD;AACpD,kEAA6D;AAC7D,sEAAkE;AAClE,oFAA+E;AAC/E,0FAAqF;AACrF,8FAAyF;AACzF,qEAAgE;AAChE,iEAA4D;AAE/C,QAAA,SAAS,GAAG,4BAAS,CAAC,UAAU,CAAC;IAC5C,QAAQ,EAAE,IAAI;IACd,WAAW,EAAE,oCAAoC;IACjD,KAAK,EAAE;QACL,OAAO,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC1B,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,oBAAoB;YACjC,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,mCAAmC;SAClD,CAAC;QACF,MAAM,EAAE,4BAAS,CAAC,UAAU,CAAC;YAC3B,WAAW,EAAE,SAAS;YACtB,WAAW,EAAE,mBAAmB;YAChC,QAAQ,EAAE,IAAI;SACf,CAAC;KACH;CACF,CAAC,CAAC;AAEU,QAAA,KAAK,GAAG,IAAA,8BAAW,EAAC;IAC/B,WAAW,EAAE,OAAO;IACpB,IAAI,EAAE,iBAAS;IACf,WAAW,EAAE,wBAAwB;IACrC,uBAAuB,EAAE,QAAQ;IACjC,OAAO,EAAE,iDAAiD;IAC1D,OAAO,EAAE,CAAC,iBAAiB,CAAC;IAC5B,OAAO,EAAE;QACP,iCAAc;QACd,6BAAY;QACZ,iDAAsB;QACtB,mDAAuB;QACvB,8BAAa;QACb,qCAAgB;QAChB,sBAAS;QACT,6CAAoB;KACrB;IACD,QAAQ,EAAE;QACR,0CAAmB;QACnB,gCAAc;QACd,yCAAkB;QAClB,8CAAqB;QACrB,8CAAqB;QACrB,6BAAY;QACZ,0BAAW;QACX,6CAAoB;QACpB,8BAAa;QACb,oBAAQ;QACR,6BAAY;QACZ,kCAAe;QACf,+CAAqB;QACrB,qDAAwB;QACxB,yDAA0B;KAC3B;CACF,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const addTrialPeriod: import("@activepieces/pieces-framework").IAction<import("@activepieces/pieces-framework").CustomAuthProperty<{
2
+ baseUrl: import("@activepieces/pieces-framework").ShortTextProperty<false>;
3
+ apiKey: import("@activepieces/pieces-framework").SecretTextProperty<true>;
4
+ }>, {
5
+ email: import("@activepieces/pieces-framework").ShortTextProperty<true>;
6
+ days: import("@activepieces/pieces-framework").NumberProperty<true>;
7
+ offerId: import("@activepieces/pieces-framework").ShortTextProperty<true>;
8
+ paymentPlanId: import("@activepieces/pieces-framework").ShortTextProperty<false>;
9
+ firstName: import("@activepieces/pieces-framework").ShortTextProperty<false>;
10
+ funnelGuard: import("@activepieces/pieces-framework").ArrayProperty<false>;
11
+ }>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addTrialPeriod = void 0;
4
+ const pieces_framework_1 = require("@activepieces/pieces-framework");
5
+ const index_1 = require("../../index");
6
+ const actions_1 = require("../common/actions");
7
+ const name = 'addTrialPeriod';
8
+ // Reshapes flat guard props into the nested `guards: { ... }` body the server
9
+ // expects. `guardSources` maps a prop name to its server guard key (e.g.
10
+ // `{ funnelGuard: 'funnel' }`). Blank entries are dropped and `guards` is omitted
11
+ // when no guard has any value.
12
+ const buildGuardedRequest = (request, guardSources) => {
13
+ const rest = Object.assign({}, request);
14
+ const guards = {};
15
+ for (const [propName, guardKey] of Object.entries(guardSources)) {
16
+ const value = rest[propName];
17
+ delete rest[propName];
18
+ const ids = Array.isArray(value)
19
+ ? value.filter((id) => typeof id === 'string' && id.trim() !== '')
20
+ : [];
21
+ if (ids.length > 0) {
22
+ guards[guardKey] = ids;
23
+ }
24
+ }
25
+ return Object.keys(guards).length > 0 ? Object.assign(Object.assign({}, rest), { guards }) : rest;
26
+ };
27
+ exports.addTrialPeriod = (0, pieces_framework_1.createAction)({
28
+ auth: index_1.coasyAuth,
29
+ name,
30
+ displayName: 'Add Trial Period',
31
+ description: "Grants a trial period on an offer to the user identified by email. Extends an existing COASY-managed subscription's nextDue or creates a new pre-cancelled subscription that auto-terminates at nextDue.",
32
+ props: {
33
+ email: pieces_framework_1.Property.ShortText({
34
+ displayName: 'Email',
35
+ description: "User's email. The user is created if it does not exist yet.",
36
+ required: true,
37
+ }),
38
+ days: pieces_framework_1.Property.Number({
39
+ displayName: 'Trial Days',
40
+ description: 'Number of trial days to grant. Must be a positive integer.',
41
+ required: true,
42
+ }),
43
+ offerId: pieces_framework_1.Property.ShortText({
44
+ displayName: 'Offer ID',
45
+ description: 'ID of the offer to grant the trial on. Must be PUBLISHED.',
46
+ required: true,
47
+ }),
48
+ paymentPlanId: pieces_framework_1.Property.ShortText({
49
+ displayName: 'Payment Plan ID',
50
+ description: "Optional specific payment plan inside the offer. Defaults to the offer's default plan.",
51
+ required: false,
52
+ }),
53
+ firstName: pieces_framework_1.Property.ShortText({
54
+ displayName: 'First Name',
55
+ description: 'Optional first name, forwarded when a new user is created.',
56
+ required: false,
57
+ }),
58
+ funnelGuard: pieces_framework_1.Property.Array({
59
+ displayName: 'Funnel Guard',
60
+ description: 'Guards against extending the trial period if the user is already a funnel participant in one of these funnels.',
61
+ required: false,
62
+ }),
63
+ },
64
+ run: (configValue) => (0, actions_1.runCoasyAction)(configValue, name, buildGuardedRequest(configValue.propsValue, { funnelGuard: 'funnel' })),
65
+ });
66
+ //# sourceMappingURL=add-trial-period.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-trial-period.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/community/coasy/src/lib/actions/add-trial-period.ts"],"names":[],"mappings":";;;AAAA,qEAAwE;AACxE,uCAAwC;AACxC,+CAAmD;AAEnD,MAAM,IAAI,GAAG,gBAAgB,CAAC;AAE9B,8EAA8E;AAC9E,yEAAyE;AACzE,kFAAkF;AAClF,+BAA+B;AAC/B,MAAM,mBAAmB,GAAG,CAC1B,OAAgC,EAChC,YAAoC,EACX,EAAE;IAC3B,MAAM,IAAI,qBAAQ,OAAO,CAAE,CAAC;IAC5B,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC9B,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YAClE,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,iCAAM,IAAI,KAAE,MAAM,IAAG,CAAC,CAAC,IAAI,CAAC;AACrE,CAAC,CAAC;AAEW,QAAA,cAAc,GAAG,IAAA,+BAAY,EAAC;IACzC,IAAI,EAAE,iBAAS;IACf,IAAI;IACJ,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EACT,0MAA0M;IAC5M,KAAK,EAAE;QACL,KAAK,EAAE,2BAAQ,CAAC,SAAS,CAAC;YACxB,WAAW,EAAE,OAAO;YACpB,WAAW,EAAE,6DAA6D;YAC1E,QAAQ,EAAE,IAAI;SACf,CAAC;QACF,IAAI,EAAE,2BAAQ,CAAC,MAAM,CAAC;YACpB,WAAW,EAAE,YAAY;YACzB,WAAW,EAAE,4DAA4D;YACzE,QAAQ,EAAE,IAAI;SACf,CAAC;QACF,OAAO,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC1B,WAAW,EAAE,UAAU;YACvB,WAAW,EAAE,2DAA2D;YACxE,QAAQ,EAAE,IAAI;SACf,CAAC;QACF,aAAa,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAChC,WAAW,EAAE,iBAAiB;YAC9B,WAAW,EACT,wFAAwF;YAC1F,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,SAAS,EAAE,2BAAQ,CAAC,SAAS,CAAC;YAC5B,WAAW,EAAE,YAAY;YACzB,WAAW,EAAE,4DAA4D;YACzE,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,WAAW,EAAE,2BAAQ,CAAC,KAAK,CAAC;YAC1B,WAAW,EAAE,cAAc;YAC3B,WAAW,EACT,gHAAgH;YAClH,QAAQ,EAAE,KAAK;SAChB,CAAC;KACH;IACD,GAAG,EAAE,CAAC,WAAW,EAAE,EAAE,CACnB,IAAA,wBAAc,EACZ,WAAW,EACX,IAAI,EACJ,mBAAmB,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CACvE;CACJ,CAAC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import { ActionContext, InputPropertyMap } from '@activepieces/pieces-framework';
2
2
  import { coasyAuth } from '../..';
3
- export declare const runCoasyAction: <T extends InputPropertyMap>(configValue: ActionContext<typeof coasyAuth, T>, action: string) => Promise<any>;
3
+ export declare const runCoasyAction: <T extends InputPropertyMap>(configValue: ActionContext<typeof coasyAuth, T>, action: string, request?: Record<string, unknown>) => Promise<any>;
@@ -3,14 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runCoasyAction = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const coasyClient_1 = require("./coasyClient");
6
- const runCoasyAction = (configValue, action) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
6
+ const runCoasyAction = (configValue, action, request) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
7
7
  var _a;
8
8
  const { propsValue, auth: authPayload } = configValue;
9
9
  const client = new coasyClient_1.CoasyClient((_a = authPayload.baseUrl) !== null && _a !== void 0 ? _a : 'https://backend.api.prod.coasy.io', authPayload.apiKey);
10
- const restPropsValue = tslib_1.__rest(propsValue, []);
11
- delete restPropsValue['auth'];
12
- const request = Object.assign({}, restPropsValue);
13
- return client.action(action, request);
10
+ const body = Object.assign({}, (request !== null && request !== void 0 ? request : propsValue));
11
+ delete body['auth'];
12
+ return client.action(action, body);
14
13
  });
15
14
  exports.runCoasyAction = runCoasyAction;
16
15
  //# sourceMappingURL=actions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/community/coasy/src/lib/common/actions.ts"],"names":[],"mappings":";;;;AAKA,+CAA4C;AAErC,MAAM,cAAc,GAAG,CAC5B,WAA+C,EAC/C,MAAc,EACd,EAAE;;IACF,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,yBAAW,CAC5B,MAAA,WAAW,CAAC,OAAO,mCAAI,mCAAmC,EAC1D,WAAW,CAAC,MAAM,CACnB,CAAC;IAEF,MAAW,cAAc,kBAAK,UAAU,EAAlC,EAAqB,CAAa,CAAC;IAEzC,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;IAE9B,MAAM,OAAO,qBAAQ,cAAc,CAAE,CAAC;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC,CAAA,CAAC;AAhBW,QAAA,cAAc,kBAgBzB"}
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../../../../../../../packages/pieces/community/coasy/src/lib/common/actions.ts"],"names":[],"mappings":";;;;AAKA,+CAA4C;AAErC,MAAM,cAAc,GAAG,CAC5B,WAA+C,EAC/C,MAAc,EACd,OAAiC,EACjC,EAAE;;IACF,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,yBAAW,CAC5B,MAAA,WAAW,CAAC,OAAO,mCAAI,mCAAmC,EAC1D,WAAW,CAAC,MAAM,CACnB,CAAC;IAEF,MAAM,IAAI,qBAAQ,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,UAAU,CAAC,CAAE,CAAC;IAC5C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IAEpB,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC,CAAA,CAAC;AAfW,QAAA,cAAc,kBAezB"}
Binary file