Skip to content

[Components] Mews #17998

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions components/mews/actions/cancel-reservation/cancel-reservation.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import app from "../../mews.app.mjs";

export default {
name: "Cancel Reservation",
description: "Cancel a reservation in Mews.",
key: "mews-cancel-reservation",
version: "0.0.1",
type: "action",
props: {
app,
reservationId: {
propDefinition: [
app,
"reservationId",
],
},
},
async run({ $ }) {
const {
app,
reservationId,
} = this;
const response = await app.reservationsCancel({
$,
data: {
ReservationIds: [
reservationId,
],
},
});
$.export("summary", "Successfully cancelled reservation");
return response;
},
};

161 changes: 161 additions & 0 deletions components/mews/actions/create-reservation/create-reservation.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import app from "../../mews.app.mjs";
import utils from "../../common/utils.mjs";

export default {
name: "Create Reservation",
description: "Create a reservation in Mews. See reservation parameters in the docs. [See the documentation](https://mews-systems.gitbook.io/connector-api/operations/reservations#add-reservations)",
key: "mews-create-reservation",
version: "0.0.1",
type: "action",
props: {
app,
serviceId: {
propDefinition: [
app,
"serviceId",
],
},
customerId: {
propDefinition: [
app,
"customerId",
],
},
startUtc: {
propDefinition: [
app,
"startUtc",
],
},
endUtc: {
propDefinition: [
app,
"endUtc",
],
},
state: {
propDefinition: [
app,
"state",
],
optional: true,
},
resourceId: {
propDefinition: [
app,
"resourceId",
],
optional: true,
},
number: {
propDefinition: [
app,
"number",
],
optional: true,
},
notes: {
propDefinition: [
app,
"notes",
],
optional: true,
},
rateId: {
propDefinition: [
app,
"rateId",
],
optional: true,
},
companyId: {
propDefinition: [
app,
"companyId",
],
optional: true,
},
travelAgencyId: {
propDefinition: [
app,
"travelAgencyId",
],
optional: true,
},
businessSegmentId: {
propDefinition: [
app,
"businessSegmentId",
],
optional: true,
},
additionalFields: {
propDefinition: [
app,
"additionalFields",
],
optional: true,
},
},
async run({ $ }) {
const {
app,
serviceId,
customerId,
startUtc,
endUtc,
state,
resourceId,
number,
notes,
rateId,
companyId,
travelAgencyId,
businessSegmentId,
additionalFields,
} = this;

const response = await app.reservationsCreate({
data: {
Reservations: [
{
ServiceId: serviceId,
CustomerId: customerId,
StartUtc: startUtc,
EndUtc: endUtc,
...(state && {
State: state,
}),
...(resourceId && {
ResourceId: resourceId,
}),
...(number && {
Number: number,
}),
...(notes && {
Notes: notes,
}),
...(rateId && {
RateId: rateId,
}),
...(companyId && {
CompanyId: companyId,
}),
...(travelAgencyId && {
TravelAgencyId: travelAgencyId,
}),
...(businessSegmentId && {
BusinessSegmentId: businessSegmentId,
}),
...(additionalFields && {
...utils.parseJson(additionalFields),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify utils.parseJson handles errors properly

Same concern as in the update action - if utils.parseJson fails silently, invalid data could be sent to the API.


🏁 Script executed:

#!/bin/bash
# Check how parseJson is used across actions
echo "Searching for parseJson usage patterns..."
rg -A 3 -B 1 "parseJson" components/mews/actions/ --type js

Length of output: 152


Let’s broaden the search to include all file types (not just “.js”) so we can locate both the definition and every usage of parseJson:


🏁 Script executed:

#!/bin/bash
# Find definition and all references to parseJson across the entire repo
echo "Searching for parseJson occurrences in all files..."
rg -n "parseJson" .

Length of output: 15746


Let’s inspect the parseJson implementation in components/mews/common/uilts.mjs to see how it handles invalid JSON:


🏁 Script executed:

#!/bin/bash
# Show the parseJson implementation in the mews common utils
sed -n '1,200p' components/mews/common/uilts.mjs

Length of output: 1164


Ensure JSON parse failures aren’t silently swallowed

The parseJson function in components/mews/common/uilts.mjs wraps JSON.parse in a try/catch and simply returns the raw string on failure. In your action:

  • components/mews/actions/create-reservation/create-reservation.mjs:151
      ...utils.parseJson(additionalFields),

an invalid JSON string will be passed straight through (and even spread into the payload as individual character properties), leading to malformed API requests.

Please add explicit error handling or a safe default around this call (for example, guard against non-object returns or default to {}), or update parseJson so it surfaces errors instead of swallowing them silently.

Targets for your fix:

  • components/mews/actions/create-reservation/create-reservation.mjs:151
  • components/mews/actions/update-reservation/update-reservation.mjs:149
🤖 Prompt for AI Agents
In components/mews/actions/create-reservation/create-reservation.mjs around line
151 and components/mews/actions/update-reservation/update-reservation.mjs around
line 149, the spread of utils.parseJson(additionalFields) can silently spread a
raw string (or other non-object) when parseJson fails; update the call to
validate the parse result and guard against non-object returns by using a safe
default (e.g., const parsed = utils.parseJson(additionalFields); const safeObj =
(parsed && typeof parsed === "object" && !Array.isArray(parsed)) ? parsed : {};
then spread safeObj) or change parseJson to throw on invalid JSON and catch it
here to default to {} before spreading so malformed JSON cannot produce
character properties in the payload.

}),
},
],
},
$,
});
$.export("summary", "Successfully created reservation");
return response;
},
};
37 changes: 37 additions & 0 deletions components/mews/actions/fetch-customers/fetch-customers.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import app from "../../mews.app.mjs";
import utils from "../../common/utils.mjs";

export default {
name: "Fetch Customers",
description: "Retrieve customers using Mews Connector API. [See the documentation](https://mews-systems.gitbook.io/connector-api/operations/customers#get-all-customers)",
key: "mews-fetch-customers",
version: "0.0.1",
type: "action",
props: {
app,
additionalFields: {
propDefinition: [
app,
"additionalFields",
],
},
},
async run({ $ }) {
const {
app,
additionalFields,
} = this;

const items = await app.paginate({
requester: app.customersGetAll,
requesterArgs: {
$,
data: utils.parseJson(additionalFields),
},
resultKey: "Customers",
});
$.export("summary", `Successfully fetched ${items.length} customers`);
return items;
},
};

37 changes: 37 additions & 0 deletions components/mews/actions/fetch-order-items/fetch-order-items.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import app from "../../mews.app.mjs";
import utils from "../../common/utils.mjs";

export default {
name: "Fetch Order Items",
description: "Retrieve order items using Mews Connector API. [See the documentation](https://mews-systems.gitbook.io/connector-api/operations/orderitems#get-all-order-items)",
key: "mews-fetch-order-items",
version: "0.0.1",
type: "action",
props: {
app,
additionalFields: {
propDefinition: [
app,
"additionalFields",
],
},
},
async run({ $ }) {
const {
app,
additionalFields,
} = this;

const items = await app.paginate({
requester: app.orderItemsGetAll,
requesterArgs: {
$,
data: utils.parseJson(additionalFields),
},
resultKey: "OrderItems",
});
$.export("summary", `Successfully fetched ${items.length} order items`);
return items;
},
};

37 changes: 37 additions & 0 deletions components/mews/actions/fetch-products/fetch-products.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import app from "../../mews.app.mjs";
import utils from "../../common/utils.mjs";

export default {
name: "Fetch Products",
description: "Retrieve products using Mews Connector API. [See the documentation](https://mews-systems.gitbook.io/connector-api/operations/products#get-all-products)",
key: "mews-fetch-products",
version: "0.0.1",
type: "action",
props: {
app,
additionalFields: {
propDefinition: [
app,
"additionalFields",
],
},
},
async run({ $ }) {
const {
app,
additionalFields,
} = this;

const items = await app.paginate({
requester: app.productsGetAll,
requesterArgs: {
$,
data: utils.parseJson(additionalFields),
},
resultKey: "Products",
});
$.export("summary", `Successfully fetched ${items.length} products`);
return items;
},
};

38 changes: 38 additions & 0 deletions components/mews/actions/fetch-reservations/fetch-reservations.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import app from "../../mews.app.mjs";
import utils from "../../common/utils.mjs";

export default {
name: "Fetch Reservations",
description: "Retrieve reservations using Mews Connector API. [See the documentation](https://mews-systems.gitbook.io/connector-api/operations/reservations#get-all-reservations-ver-2023-06-06)",
key: "mews-fetch-reservations",
version: "0.0.1",
type: "action",
props: {
app,
additionalFields: {
propDefinition: [
app,
"additionalFields",
],
},
},
async run({ $ }) {
const {
app,
additionalFields,
} = this;

const items = await app.paginate({
requester: app.reservationsGetAll,
requesterArgs: {
$,
data: utils.parseJson(additionalFields),
},
resultKey: "Reservations",
});

$.export("summary", `Successfully fetched ${items.length} reservations`);
return items;
},
};

Loading
Loading