@prismatic-io/components-fluent-commerce 0.0.0-stage → 0.0.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.
@@ -0,0 +1,1240 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ let _prismatic_io_spectral = require("@prismatic-io/spectral");
24
+ let _prismatic_io_spectral_http = require("@prismatic-io/spectral/http");
25
+ let graphql_request = require("graphql-request");
26
+ let url_join = require("url-join");
27
+ url_join = __toESM(url_join);
28
+ let lodash_merge = require("lodash.merge");
29
+ lodash_merge = __toESM(lodash_merge);
30
+ //#region src/connections/fluentCommerceOAuthPassword.ts
31
+ const fluentCommerceOAuthPassword = (0, _prismatic_io_spectral.connection)({
32
+ key: "fluent-password-grant",
33
+ display: {
34
+ description: "Authenticate requests to Fluent Commerce using a username and password",
35
+ label: "Fluent Commerce OAuth 2.0 Password Grant"
36
+ },
37
+ inputs: {
38
+ host: {
39
+ label: "Fluent Host",
40
+ placeholder: "https://REPLACE-ME.api.fluentretail.com",
41
+ type: "string",
42
+ required: true,
43
+ shown: true,
44
+ comments: "The retailer's Fluent API endpoint",
45
+ example: "https://REPLACE-ME.api.fluentretail.com"
46
+ },
47
+ username: {
48
+ label: "Retailer Username",
49
+ placeholder: "Enter username",
50
+ type: "string",
51
+ required: true,
52
+ shown: true,
53
+ comments: "The retailer's username",
54
+ example: "john_doe"
55
+ },
56
+ password: {
57
+ label: "Retailer Password",
58
+ placeholder: "Enter password",
59
+ type: "password",
60
+ required: true,
61
+ shown: true,
62
+ comments: "The retailer's password"
63
+ },
64
+ clientId: {
65
+ label: "OAuth 2.0 Client ID",
66
+ placeholder: "Enter client ID",
67
+ type: "string",
68
+ required: true,
69
+ shown: true,
70
+ comments: "A client ID obtained from Fluent support"
71
+ },
72
+ clientSecret: {
73
+ label: "OAuth 2.0 Client Secret",
74
+ placeholder: "Enter client secret",
75
+ type: "password",
76
+ required: true,
77
+ shown: true,
78
+ comments: "A client secret obtained from Fluent support"
79
+ }
80
+ }
81
+ });
82
+ //#endregion
83
+ //#region src/connections/index.ts
84
+ var connections_default = [fluentCommerceOAuthPassword];
85
+ //#endregion
86
+ //#region src/client.ts
87
+ const createFluentClient = async (connection, debug = false, logger) => {
88
+ if (connection.key !== fluentCommerceOAuthPassword.key) throw new _prismatic_io_spectral.ConnectionError(connection, `Received unexpected connection type: ${connection.key}`);
89
+ const { clientId, clientSecret, host, password, username } = connection.fields;
90
+ let access_token;
91
+ const axiosClient = (0, _prismatic_io_spectral_http.createClient)({ debug: false });
92
+ try {
93
+ const oauthUrl = (0, url_join.default)(_prismatic_io_spectral.util.types.toString(host), "oauth/token");
94
+ const { data: authResponseData } = await axiosClient.post(oauthUrl, null, { params: {
95
+ client_id: clientId,
96
+ client_secret: clientSecret,
97
+ grant_type: "password",
98
+ scope: "api",
99
+ password,
100
+ username
101
+ } });
102
+ access_token = authResponseData.access_token;
103
+ } catch (error) {
104
+ throw new Error(`An error occurred during authentication. Please ensure your username, password, client ID, client secret and endpoint URL are correct. Error: ${error}`);
105
+ }
106
+ if (!access_token) throw new Error("Fluent returned no access token. Please ensure your username, password, client ID, client secret and endpoint URL are correct.");
107
+ return new graphql_request.GraphQLClient((0, url_join.default)(_prismatic_io_spectral.util.types.toString(host), "graphql"), {
108
+ headers: { authorization: `bearer ${access_token}` },
109
+ ...debug && logger ? { requestMiddleware: (request) => {
110
+ logger.debug(`Fluent GraphQL request: ${request.body}`);
111
+ return request;
112
+ } } : {}
113
+ });
114
+ };
115
+ //#endregion
116
+ //#region src/examplePayloads.ts
117
+ const createProductExamplePayload = { data: { createStandardProduct: {
118
+ id: "03440122-ea39-499b-83aa-f08b2614daf3",
119
+ ref: "TESTPRD3"
120
+ } } };
121
+ const createCustomerExamplePayload = { data: { createCustomer: {
122
+ id: "744793",
123
+ username: "jdoe@email.com",
124
+ primaryEmail: "jdoe@email.com",
125
+ primaryPhone: "+123456789",
126
+ firstName: "John",
127
+ lastName: "Doe",
128
+ timezone: "Australia/Sydney",
129
+ country: "Australia",
130
+ promotionOptIn: true,
131
+ retailer: { id: "34" },
132
+ attributes: [{
133
+ name: "loyaltyTier",
134
+ type: "STRING",
135
+ value: "Gold"
136
+ }]
137
+ } } };
138
+ const getCustomerByEmailAddressExamplePayload = { data: { customers: { edges: [{ node: {
139
+ id: "744793",
140
+ ref: "CUST-744793",
141
+ firstName: "John",
142
+ lastName: "Doe",
143
+ username: "jdoe@email.com",
144
+ primaryEmail: "jdoe@email.com",
145
+ primaryPhone: "+123456789",
146
+ timezone: "Australia/Sydney",
147
+ attributes: [{
148
+ name: "loyaltyTier",
149
+ type: "STRING"
150
+ }]
151
+ } }] } } };
152
+ const getCurrentUserExamplePayload = { data: { me: {
153
+ id: "744793",
154
+ username: "admin@fluentretail.com",
155
+ title: "Administrator",
156
+ firstName: "Admin",
157
+ lastName: "User",
158
+ primaryEmail: "admin@fluentretail.com",
159
+ primaryPhone: "+61400000000",
160
+ type: "DEFAULT",
161
+ status: "ACTIVE",
162
+ attributes: [{
163
+ name: "defaultLanguage",
164
+ type: "STRING",
165
+ value: "en"
166
+ }],
167
+ department: "IT",
168
+ country: "Australia",
169
+ timezone: "Australia/Sydney",
170
+ language: {
171
+ value: "en",
172
+ label: "English"
173
+ },
174
+ promotionOptIn: false,
175
+ primaryRetailer: {
176
+ id: "34",
177
+ tradingName: "Fluent Retail"
178
+ },
179
+ primaryLocation: {
180
+ id: "1001",
181
+ type: "STORE",
182
+ status: "ACTIVE",
183
+ name: "Sydney CBD"
184
+ },
185
+ roles: [{ role: {
186
+ id: "1",
187
+ name: "ADMIN",
188
+ permissions: [{ name: "MANAGE_USERS" }]
189
+ } }],
190
+ apps: [{
191
+ id: "101",
192
+ name: "Fluent OMS",
193
+ version: {
194
+ major: 4,
195
+ minor: 2,
196
+ patch: 1
197
+ }
198
+ }]
199
+ } } };
200
+ const genericRequestExamplePayload = { data: { me: {
201
+ id: "744793",
202
+ username: "admin@fluentretail.com",
203
+ primaryEmail: "admin@fluentretail.com"
204
+ } } };
205
+ const pollChangesTriggerExamplePayload = { payload: {
206
+ headers: {},
207
+ queryParameters: {},
208
+ rawBody: { data: null },
209
+ body: { data: {
210
+ created: [{
211
+ id: "ORD-1042",
212
+ ref: "WEB-000142",
213
+ type: "STANDARD",
214
+ status: "CREATED",
215
+ createdOn: "2026-05-26T14:30:00.000Z",
216
+ updatedOn: "2026-05-26T14:30:00.000Z"
217
+ }],
218
+ updated: [{
219
+ id: "ORD-980",
220
+ ref: "WEB-000087",
221
+ type: "STANDARD",
222
+ status: "FULFILLED",
223
+ createdOn: "2026-04-12T09:00:00.000Z",
224
+ updatedOn: "2026-05-26T15:45:00.000Z"
225
+ }]
226
+ } },
227
+ pathFragment: "",
228
+ webhookUrls: {},
229
+ webhookApiKeys: {},
230
+ invokeUrl: "",
231
+ executionId: "RXhhbXBsZUV4ZWN1dGlvblJlc3VsdElk",
232
+ customer: {
233
+ id: "testCustomerId",
234
+ name: "Test Customer",
235
+ externalId: "testExternalId"
236
+ },
237
+ instance: {
238
+ id: "testInstanceId",
239
+ name: "Test Instance"
240
+ },
241
+ user: {
242
+ id: "testUserId",
243
+ email: "user@example.com",
244
+ name: "Test User",
245
+ externalId: "testUserExternalId"
246
+ },
247
+ integration: {
248
+ id: "testIntegrationId",
249
+ name: "Test Integration",
250
+ versionSequenceId: "1",
251
+ externalVersion: ""
252
+ },
253
+ flow: {
254
+ id: "testFlowId",
255
+ name: "Test Flow",
256
+ stableId: "testFlowStableId"
257
+ },
258
+ startedAt: "2024-01-15T00:00:00.000Z",
259
+ globalDebug: false
260
+ } };
261
+ //#endregion
262
+ //#region src/inputs/common.ts
263
+ const connectionInput = (0, _prismatic_io_spectral.input)({
264
+ label: "Connection",
265
+ type: "connection",
266
+ required: true,
267
+ comments: "The Fluent Commerce connection to use."
268
+ });
269
+ //#endregion
270
+ //#region src/constants.ts
271
+ const LOOK_BACK_DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
272
+ const POLL_ORDERS_QUERY = graphql_request.gql`
273
+ query PollOrders($from: DateTime!, $to: DateTime!, $first: Int!, $after: String, $retailerId: [Int!]) {
274
+ orders(updatedOn: { from: $from, to: $to }, first: $first, after: $after, retailerId: $retailerId) {
275
+ edges {
276
+ node {
277
+ id
278
+ ref
279
+ type
280
+ status
281
+ createdOn
282
+ updatedOn
283
+ }
284
+ }
285
+ pageInfo {
286
+ hasNextPage
287
+ endCursor
288
+ }
289
+ }
290
+ }
291
+ `;
292
+ //#endregion
293
+ //#region src/util/clean.ts
294
+ const toOptionalString = (value) => _prismatic_io_spectral.util.types.toString(value) || void 0;
295
+ const toOptionalNumber = (value) => value ? _prismatic_io_spectral.util.types.toNumber(value) : void 0;
296
+ const toOptionalObject = (value) => value ? _prismatic_io_spectral.util.types.toObject(value) : void 0;
297
+ const lookBackDateClean = (value) => {
298
+ if (value === void 0 || value === null) return "";
299
+ const raw = typeof value === "string" ? value.trim() : String(value);
300
+ if (raw === "") return "";
301
+ const match = typeof value === "string" ? raw.match(LOOK_BACK_DATE_PATTERN) : null;
302
+ if (!match) throw new Error(`Look-back Date must be a date in YYYY-MM-DD format. Received: ${raw}`);
303
+ const [, yearStr, monthStr, dayStr] = match;
304
+ const year = Number(yearStr);
305
+ const month = Number(monthStr);
306
+ const day = Number(dayStr);
307
+ const parsed = new Date(Date.UTC(year, month - 1, day));
308
+ if (parsed.getUTCFullYear() !== year || parsed.getUTCMonth() !== month - 1 || parsed.getUTCDate() !== day) throw new Error(`Look-back Date must be a date in YYYY-MM-DD format. Received: ${raw}`);
309
+ if (parsed.getTime() > Date.now()) throw new Error(`Look-back Date cannot be a future date. Received: ${raw}`);
310
+ return parsed.toISOString();
311
+ };
312
+ const toStringAttributes = (attributes) => {
313
+ if (Array.isArray(attributes)) return attributes.map((attribute) => ({
314
+ name: attribute.key,
315
+ type: "STRING",
316
+ value: attribute.value
317
+ }));
318
+ return [];
319
+ };
320
+ //#endregion
321
+ //#region src/util/polling.ts
322
+ const fetchFluentOrdersInWindow = async (connection, window, retailerId, maxPages) => {
323
+ const client = await createFluentClient(connection);
324
+ const records = [];
325
+ let after = window.after;
326
+ for (let page = 0; page < maxPages; page++) {
327
+ const variables = {
328
+ from: window.from,
329
+ to: window.to,
330
+ first: 50,
331
+ after,
332
+ retailerId: retailerId || null
333
+ };
334
+ const data = await client.request(POLL_ORDERS_QUERY, variables);
335
+ const edges = data?.orders?.edges ?? [];
336
+ for (const edge of edges) if (edge?.node) records.push(edge.node);
337
+ const pageInfo = data?.orders?.pageInfo;
338
+ if (!pageInfo?.hasNextPage) return {
339
+ records,
340
+ truncated: false,
341
+ after: null
342
+ };
343
+ if (!pageInfo.endCursor) throw new Error("Fluent reported more orders but returned no endCursor to continue from.");
344
+ after = pageInfo.endCursor;
345
+ }
346
+ return {
347
+ records,
348
+ truncated: true,
349
+ after
350
+ };
351
+ };
352
+ const resolveFluentOrderChanges = (data) => {
353
+ const changesObject = data ?? {
354
+ created: [],
355
+ updated: []
356
+ };
357
+ return [...(changesObject.created ?? []).map((record) => ({
358
+ changeType: "created",
359
+ record
360
+ })), ...(changesObject.updated ?? []).map((record) => ({
361
+ changeType: "updated",
362
+ record
363
+ }))];
364
+ };
365
+ //#endregion
366
+ //#region src/inputs/customers.ts
367
+ const retailerId$1 = (0, _prismatic_io_spectral.input)({
368
+ label: "Retailer ID",
369
+ type: "string",
370
+ example: "34",
371
+ placeholder: "Enter retailer ID",
372
+ required: true,
373
+ clean: _prismatic_io_spectral.util.types.toString,
374
+ comments: "The ID of the retailer (a number)"
375
+ });
376
+ const customerEmail = (0, _prismatic_io_spectral.input)({
377
+ label: "Customer Email",
378
+ type: "string",
379
+ example: "test@example.com",
380
+ placeholder: "Enter customer email",
381
+ required: true,
382
+ clean: _prismatic_io_spectral.util.types.toString,
383
+ comments: "The email address of the customer"
384
+ });
385
+ const firstName = (0, _prismatic_io_spectral.input)({
386
+ label: "First Name",
387
+ type: "string",
388
+ example: "John",
389
+ placeholder: "Enter first name",
390
+ required: true,
391
+ clean: _prismatic_io_spectral.util.types.toString,
392
+ comments: "The first name of the customer (required)"
393
+ });
394
+ const lastName = (0, _prismatic_io_spectral.input)({
395
+ label: "Last Name",
396
+ type: "string",
397
+ example: "Doe",
398
+ placeholder: "Enter last name",
399
+ required: false,
400
+ clean: toOptionalString,
401
+ comments: "The last name of the customer"
402
+ });
403
+ const phoneNumber = (0, _prismatic_io_spectral.input)({
404
+ label: "Phone Number",
405
+ type: "string",
406
+ example: "+61412345678",
407
+ placeholder: "Enter phone number",
408
+ required: false,
409
+ clean: toOptionalString,
410
+ comments: "The customer's phone number"
411
+ });
412
+ const country = (0, _prismatic_io_spectral.input)({
413
+ label: "Country",
414
+ type: "string",
415
+ example: "Australia",
416
+ placeholder: "Enter country",
417
+ required: false,
418
+ clean: toOptionalString,
419
+ comments: "The customer's country"
420
+ });
421
+ const timezone = (0, _prismatic_io_spectral.input)({
422
+ label: "Time Zone",
423
+ type: "string",
424
+ example: "UTC+5",
425
+ placeholder: "Enter time zone",
426
+ required: false,
427
+ clean: toOptionalString,
428
+ comments: "The customer's time zone"
429
+ });
430
+ const promotionOptIn = (0, _prismatic_io_spectral.input)({
431
+ label: "Promotion Opt In",
432
+ type: "boolean",
433
+ required: true,
434
+ clean: _prismatic_io_spectral.util.types.toBool,
435
+ comments: "When true, the customer is opted in to receive promotional communications."
436
+ });
437
+ const attributes = (0, _prismatic_io_spectral.input)({
438
+ label: "Attributes",
439
+ type: "string",
440
+ required: false,
441
+ collection: "keyvaluelist",
442
+ clean: toStringAttributes,
443
+ comments: "Custom attributes to apply to the customer. Each key becomes the attribute name, and each value is stored as a STRING attribute."
444
+ });
445
+ const emailAddress = (0, _prismatic_io_spectral.input)({
446
+ label: "Customer Email Address",
447
+ type: "string",
448
+ example: "test@example.com",
449
+ placeholder: "Enter customer email address",
450
+ required: true,
451
+ clean: _prismatic_io_spectral.util.types.toString,
452
+ comments: "The customer's email address"
453
+ });
454
+ const createCustomerInputs = {
455
+ connection: connectionInput,
456
+ retailerId: retailerId$1,
457
+ customerEmail,
458
+ firstName,
459
+ promotionOptIn,
460
+ lastName,
461
+ phoneNumber,
462
+ country,
463
+ timezone,
464
+ attributes
465
+ };
466
+ const getCustomerByEmailAddressInputs = {
467
+ connection: connectionInput,
468
+ emailAddress
469
+ };
470
+ const genericRequestInputs = {
471
+ connection: connectionInput,
472
+ query: (0, _prismatic_io_spectral.input)({
473
+ label: "Query or Mutation",
474
+ type: "code",
475
+ required: true,
476
+ language: "graphql",
477
+ default: `{
478
+ me {
479
+ id
480
+ username
481
+ primaryEmail
482
+ }
483
+ }`,
484
+ placeholder: "Enter GraphQL query or mutation",
485
+ clean: _prismatic_io_spectral.util.types.toString,
486
+ comments: "The GraphQL query or mutation to send to the Fluent Commerce API."
487
+ }),
488
+ variables: (0, _prismatic_io_spectral.input)({
489
+ label: "Variables",
490
+ type: "string",
491
+ required: false,
492
+ collection: "keyvaluelist",
493
+ clean: (val) => _prismatic_io_spectral.util.types.keyValPairListToObject(val),
494
+ comments: "Key-value pairs passed to the query as GraphQL variables."
495
+ }),
496
+ variablesObject: (0, _prismatic_io_spectral.input)({
497
+ label: "Variables Object",
498
+ type: "code",
499
+ language: "json",
500
+ required: false,
501
+ example: "{\"retailerId\": \"34\"}",
502
+ placeholder: "Enter GraphQL variables as JSON",
503
+ clean: toOptionalObject,
504
+ comments: "A JSON object of GraphQL variables, for values that are not strings. Merged with Variables; on a shared key, this value wins."
505
+ })
506
+ };
507
+ const getCurrentUserInputs = { connection: connectionInput };
508
+ const createProductInputs = {
509
+ connection: connectionInput,
510
+ productCatalogueRef: (0, _prismatic_io_spectral.input)({
511
+ label: "Product Catalogue Ref (ID)",
512
+ type: "string",
513
+ required: true,
514
+ example: "FCRG:PC:MASTER",
515
+ placeholder: "Enter product catalogue ref",
516
+ clean: _prismatic_io_spectral.util.types.toString,
517
+ comments: "The reference ID (ref) of an existing product catalog"
518
+ }),
519
+ productRef: (0, _prismatic_io_spectral.input)({
520
+ label: "Product Ref ID",
521
+ type: "string",
522
+ required: true,
523
+ example: "TESTPRD",
524
+ placeholder: "Enter product ref",
525
+ clean: _prismatic_io_spectral.util.types.toString,
526
+ comments: "The reference ID (ref) of the new product (must be unique)"
527
+ }),
528
+ productType: (0, _prismatic_io_spectral.input)({
529
+ label: "Product Type",
530
+ type: "string",
531
+ required: true,
532
+ example: "STANDARD",
533
+ default: "STANDARD",
534
+ placeholder: "Enter product type",
535
+ clean: _prismatic_io_spectral.util.types.toString,
536
+ comments: "The type of the product"
537
+ }),
538
+ productName: (0, _prismatic_io_spectral.input)({
539
+ label: "Product Name",
540
+ type: "string",
541
+ required: true,
542
+ example: "Widget",
543
+ placeholder: "Enter product name",
544
+ clean: _prismatic_io_spectral.util.types.toString,
545
+ comments: "The name of the product (not required to be unique)"
546
+ }),
547
+ productSummary: (0, _prismatic_io_spectral.input)({
548
+ label: "Product Summary / Description",
549
+ type: "string",
550
+ required: true,
551
+ example: "Widgets: the new whatsits",
552
+ placeholder: "Enter product summary",
553
+ clean: _prismatic_io_spectral.util.types.toString,
554
+ comments: "A short description of the product, stored as the product's summary."
555
+ }),
556
+ gtin: (0, _prismatic_io_spectral.input)({
557
+ label: "Global Trade Item Number (GTIN)",
558
+ type: "string",
559
+ required: true,
560
+ example: "012345678905",
561
+ placeholder: "Enter GTIN",
562
+ clean: _prismatic_io_spectral.util.types.toString,
563
+ comments: "The global trade number of the product"
564
+ }),
565
+ priceCurrency: (0, _prismatic_io_spectral.input)({
566
+ label: "Price Currency",
567
+ type: "string",
568
+ required: true,
569
+ example: "USD",
570
+ placeholder: "Enter price currency",
571
+ clean: _prismatic_io_spectral.util.types.toString,
572
+ comments: "Type of currency the price is in (USD, YEN, GBP, etc)"
573
+ }),
574
+ priceValue: (0, _prismatic_io_spectral.input)({
575
+ label: "Price Value",
576
+ type: "string",
577
+ required: true,
578
+ example: "1300",
579
+ placeholder: "Enter price value",
580
+ clean: _prismatic_io_spectral.util.types.toNumber,
581
+ comments: "The price of the product (must be a floating-point number)"
582
+ })
583
+ };
584
+ const pollChangesInputs = {
585
+ connection: connectionInput,
586
+ lookBackDate: (0, _prismatic_io_spectral.input)({
587
+ label: "Look-back Date",
588
+ placeholder: "Enter look-back date (YYYY-MM-DD)",
589
+ type: "string",
590
+ required: false,
591
+ comments: "The date the initial sync starts from, in YYYY-MM-DD format. Cannot be a future date. Leave empty to start from the first recurrence with no backfill. When set, the initial sync seeds each record modified on or after this date once, ignoring the field and visibility filters.",
592
+ example: "2026-01-01",
593
+ clean: lookBackDateClean
594
+ }),
595
+ retailerId: (0, _prismatic_io_spectral.input)({
596
+ label: "Retailer ID",
597
+ type: "string",
598
+ required: false,
599
+ example: "34",
600
+ comments: "Optional Fluent retailer ID to scope the polling query. When omitted, the connection's default tenant scope applies.",
601
+ clean: toOptionalNumber
602
+ }),
603
+ showNewRecords: (0, _prismatic_io_spectral.input)({
604
+ label: "Show New Records",
605
+ type: "boolean",
606
+ required: false,
607
+ default: "true",
608
+ comments: "When enabled, orders whose `createdOn` falls after the last poll will be emitted in the `created` array.",
609
+ clean: _prismatic_io_spectral.util.types.toBool
610
+ }),
611
+ showUpdatedRecords: (0, _prismatic_io_spectral.input)({
612
+ label: "Show Updated Records",
613
+ type: "boolean",
614
+ required: false,
615
+ default: "true",
616
+ comments: "When enabled, orders whose `updatedOn` falls after the last poll but were created earlier will be emitted in the `updated` array.",
617
+ clean: _prismatic_io_spectral.util.types.toBool
618
+ })
619
+ };
620
+ //#endregion
621
+ //#region src/outputSchemas.ts
622
+ const attributeItemSchema = {
623
+ type: ["object", "null"],
624
+ properties: {
625
+ name: { type: "string" },
626
+ type: { type: "string" },
627
+ value: { type: [
628
+ "string",
629
+ "number",
630
+ "boolean",
631
+ "object",
632
+ "array"
633
+ ] }
634
+ },
635
+ required: [
636
+ "name",
637
+ "type",
638
+ "value"
639
+ ]
640
+ };
641
+ const createCustomerOutputSchema = {
642
+ type: "object",
643
+ properties: { createCustomer: {
644
+ type: ["object", "null"],
645
+ properties: {
646
+ id: { type: "string" },
647
+ username: { type: ["string", "null"] },
648
+ primaryEmail: { type: ["string", "null"] },
649
+ primaryPhone: { type: ["string", "null"] },
650
+ firstName: { type: ["string", "null"] },
651
+ lastName: { type: ["string", "null"] },
652
+ timezone: { type: ["string", "null"] },
653
+ country: { type: ["string", "null"] },
654
+ promotionOptIn: { type: ["boolean", "null"] },
655
+ retailer: {
656
+ type: ["object", "null"],
657
+ properties: { id: { type: "string" } },
658
+ required: ["id"]
659
+ },
660
+ attributes: {
661
+ type: ["array", "null"],
662
+ items: attributeItemSchema
663
+ }
664
+ },
665
+ required: [
666
+ "id",
667
+ "username",
668
+ "primaryEmail",
669
+ "primaryPhone",
670
+ "firstName",
671
+ "lastName",
672
+ "timezone",
673
+ "country",
674
+ "promotionOptIn",
675
+ "retailer",
676
+ "attributes"
677
+ ]
678
+ } },
679
+ required: ["createCustomer"]
680
+ };
681
+ const getCustomerByEmailAddressOutputSchema = {
682
+ type: "object",
683
+ properties: { customers: {
684
+ type: ["object", "null"],
685
+ properties: { edges: {
686
+ type: ["array", "null"],
687
+ items: {
688
+ type: ["object", "null"],
689
+ properties: { node: {
690
+ type: ["object", "null"],
691
+ properties: {
692
+ id: { type: "string" },
693
+ ref: { type: ["string", "null"] },
694
+ firstName: { type: ["string", "null"] },
695
+ lastName: { type: ["string", "null"] },
696
+ username: { type: ["string", "null"] },
697
+ primaryEmail: { type: ["string", "null"] },
698
+ primaryPhone: { type: ["string", "null"] },
699
+ timezone: { type: ["string", "null"] },
700
+ attributes: {
701
+ type: ["array", "null"],
702
+ items: {
703
+ type: ["object", "null"],
704
+ properties: {
705
+ name: { type: "string" },
706
+ type: { type: "string" }
707
+ },
708
+ required: ["name", "type"]
709
+ }
710
+ }
711
+ },
712
+ required: [
713
+ "id",
714
+ "ref",
715
+ "firstName",
716
+ "lastName",
717
+ "username",
718
+ "primaryEmail",
719
+ "primaryPhone",
720
+ "timezone",
721
+ "attributes"
722
+ ]
723
+ } },
724
+ required: ["node"]
725
+ }
726
+ } },
727
+ required: ["edges"]
728
+ } },
729
+ required: ["customers"]
730
+ };
731
+ const getCurrentUserOutputSchema = {
732
+ type: "object",
733
+ properties: { me: {
734
+ type: ["object", "null"],
735
+ properties: {
736
+ id: { type: "string" },
737
+ username: { type: "string" },
738
+ title: { type: ["string", "null"] },
739
+ firstName: { type: ["string", "null"] },
740
+ lastName: { type: ["string", "null"] },
741
+ primaryEmail: { type: ["string", "null"] },
742
+ primaryPhone: { type: ["string", "null"] },
743
+ type: { type: "string" },
744
+ status: { type: ["string", "null"] },
745
+ attributes: {
746
+ type: ["array", "null"],
747
+ items: attributeItemSchema
748
+ },
749
+ department: { type: ["string", "null"] },
750
+ country: { type: ["string", "null"] },
751
+ timezone: { type: ["string", "null"] },
752
+ language: {
753
+ type: ["object", "null"],
754
+ properties: {
755
+ value: { type: ["string", "null"] },
756
+ label: { type: ["string", "null"] }
757
+ },
758
+ required: ["value", "label"]
759
+ },
760
+ promotionOptIn: { type: ["boolean", "null"] },
761
+ primaryRetailer: {
762
+ type: ["object", "null"],
763
+ properties: {
764
+ id: { type: "string" },
765
+ tradingName: { type: ["string", "null"] }
766
+ },
767
+ required: ["id", "tradingName"]
768
+ },
769
+ primaryLocation: {
770
+ type: ["object", "null"],
771
+ properties: {
772
+ id: { type: "string" },
773
+ type: { type: ["string", "null"] },
774
+ status: { type: ["string", "null"] },
775
+ name: { type: ["string", "null"] }
776
+ },
777
+ required: [
778
+ "id",
779
+ "type",
780
+ "status",
781
+ "name"
782
+ ]
783
+ },
784
+ roles: {
785
+ type: ["array", "null"],
786
+ items: {
787
+ type: ["object", "null"],
788
+ properties: { role: {
789
+ type: "object",
790
+ properties: {
791
+ id: { type: "string" },
792
+ name: { type: "string" },
793
+ permissions: {
794
+ type: ["array", "null"],
795
+ items: {
796
+ type: ["object", "null"],
797
+ properties: { name: { type: "string" } },
798
+ required: ["name"]
799
+ }
800
+ }
801
+ },
802
+ required: [
803
+ "id",
804
+ "name",
805
+ "permissions"
806
+ ]
807
+ } },
808
+ required: ["role"]
809
+ }
810
+ },
811
+ apps: {
812
+ type: ["array", "null"],
813
+ items: {
814
+ type: ["object", "null"],
815
+ properties: {
816
+ id: { type: "string" },
817
+ name: { type: "string" },
818
+ version: {
819
+ type: "object",
820
+ properties: {
821
+ major: { type: "integer" },
822
+ minor: { type: "integer" },
823
+ patch: { type: "integer" }
824
+ },
825
+ required: [
826
+ "major",
827
+ "minor",
828
+ "patch"
829
+ ]
830
+ }
831
+ },
832
+ required: [
833
+ "id",
834
+ "name",
835
+ "version"
836
+ ]
837
+ }
838
+ }
839
+ },
840
+ required: [
841
+ "id",
842
+ "username",
843
+ "title",
844
+ "firstName",
845
+ "lastName",
846
+ "primaryEmail",
847
+ "primaryPhone",
848
+ "type",
849
+ "status",
850
+ "attributes",
851
+ "department",
852
+ "country",
853
+ "timezone",
854
+ "language",
855
+ "promotionOptIn",
856
+ "primaryRetailer",
857
+ "primaryLocation",
858
+ "roles",
859
+ "apps"
860
+ ]
861
+ } },
862
+ required: ["me"]
863
+ };
864
+ const createProductOutputSchema = {
865
+ type: "object",
866
+ properties: { createStandardProduct: {
867
+ type: ["object", "null"],
868
+ properties: {
869
+ id: { type: "string" },
870
+ ref: { type: "string" }
871
+ },
872
+ required: ["id", "ref"]
873
+ } },
874
+ required: ["createStandardProduct"]
875
+ };
876
+ //#endregion
877
+ //#region src/actions/customers/index.ts
878
+ var customers_default = {
879
+ createCustomer: (0, _prismatic_io_spectral.action)({
880
+ display: {
881
+ label: "Create Customer",
882
+ description: "Create a new customer"
883
+ },
884
+ inputs: createCustomerInputs,
885
+ outputSchema: (0, _prismatic_io_spectral.outputSchema)({
886
+ type: "actionOutput",
887
+ schema: createCustomerOutputSchema
888
+ }),
889
+ performSafety: "notAllowed",
890
+ perform: async (context, params) => {
891
+ const client = await createFluentClient(params.connection, context.debug.enabled, context.logger);
892
+ const query = graphql_request.gql`
893
+ mutation createCustomer(
894
+ $retailerId: ID!
895
+ $customerEmail: String!
896
+ $firstName: String!
897
+ $lastName: String
898
+ $phoneNumber: String
899
+ $country: String
900
+ $timezone: String
901
+ $attributes: [AttributeInput]
902
+ $promotionOptIn: Boolean!
903
+ ) {
904
+ createCustomer(
905
+ input: {
906
+ username: $customerEmail
907
+ firstName: $firstName
908
+ lastName: $lastName
909
+ primaryEmail: $customerEmail
910
+ primaryPhone: $phoneNumber
911
+ promotionOptIn: $promotionOptIn
912
+ timezone: $timezone
913
+ country: $country
914
+ retailer: { id: $retailerId }
915
+ attributes: $attributes
916
+ }
917
+ ) {
918
+ id
919
+ username
920
+ primaryEmail
921
+ primaryPhone
922
+ firstName
923
+ lastName
924
+ timezone
925
+ country
926
+ promotionOptIn
927
+ retailer {
928
+ id
929
+ }
930
+ attributes {
931
+ name
932
+ type
933
+ value
934
+ }
935
+ }
936
+ }
937
+ `;
938
+ const variables = {
939
+ retailerId: params.retailerId,
940
+ customerEmail: params.customerEmail,
941
+ firstName: params.firstName,
942
+ lastName: params.lastName,
943
+ phoneNumber: params.phoneNumber,
944
+ promotionOptIn: params.promotionOptIn,
945
+ country: params.country,
946
+ timezone: params.timezone,
947
+ attributes: params.attributes
948
+ };
949
+ return { data: await client.request(query, variables) };
950
+ },
951
+ examplePerform: async () => createCustomerExamplePayload,
952
+ examplePayload: createCustomerExamplePayload
953
+ }),
954
+ getCustomerByEmailAddress: (0, _prismatic_io_spectral.action)({
955
+ display: {
956
+ label: "Get Customer by Email",
957
+ description: "Find a customer by their email address"
958
+ },
959
+ inputs: getCustomerByEmailAddressInputs,
960
+ outputSchema: (0, _prismatic_io_spectral.outputSchema)({
961
+ type: "actionOutput",
962
+ schema: getCustomerByEmailAddressOutputSchema
963
+ }),
964
+ performSafety: "safe",
965
+ perform: async (context, params) => {
966
+ const client = await createFluentClient(params.connection, context.debug.enabled, context.logger);
967
+ const query = graphql_request.gql`
968
+ query GetCustomerByEmailAddress($emailAddress: String) {
969
+ customers(primaryEmail: [$emailAddress]) {
970
+ edges {
971
+ node {
972
+ id
973
+ ref
974
+ firstName
975
+ lastName
976
+ username
977
+ primaryEmail
978
+ primaryPhone
979
+ timezone
980
+ attributes {
981
+ name
982
+ type
983
+ }
984
+ }
985
+ }
986
+ }
987
+ }
988
+ `;
989
+ const variables = { emailAddress: params.emailAddress };
990
+ return { data: await client.request(query, variables) };
991
+ },
992
+ examplePayload: getCustomerByEmailAddressExamplePayload
993
+ })
994
+ };
995
+ //#endregion
996
+ //#region src/actions/misc/index.ts
997
+ var misc_default = {
998
+ genericRequest: (0, _prismatic_io_spectral.action)({
999
+ display: {
1000
+ label: "Generic GraphQL Request",
1001
+ description: "Issue any GraphQL query or mutation with variables"
1002
+ },
1003
+ inputs: genericRequestInputs,
1004
+ performSafety: "notAllowed",
1005
+ perform: async (context, params) => {
1006
+ return { data: await (await createFluentClient(params.connection, context.debug.enabled, context.logger)).request(params.query, (0, lodash_merge.default)(params.variables, params.variablesObject)) };
1007
+ },
1008
+ examplePayload: genericRequestExamplePayload
1009
+ }),
1010
+ getCurrentUser: (0, _prismatic_io_spectral.action)({
1011
+ display: {
1012
+ label: "Get Current User",
1013
+ description: "Get information about the currently authenticated user"
1014
+ },
1015
+ inputs: getCurrentUserInputs,
1016
+ outputSchema: (0, _prismatic_io_spectral.outputSchema)({
1017
+ type: "actionOutput",
1018
+ schema: getCurrentUserOutputSchema
1019
+ }),
1020
+ performSafety: "safe",
1021
+ perform: async (context, params) => {
1022
+ const client = await createFluentClient(params.connection, context.debug.enabled, context.logger);
1023
+ const query = graphql_request.gql`
1024
+ {
1025
+ me {
1026
+ id
1027
+ username
1028
+ title
1029
+ firstName
1030
+ lastName
1031
+ primaryEmail
1032
+ primaryPhone
1033
+ type
1034
+ status
1035
+ attributes {
1036
+ name
1037
+ type
1038
+ value
1039
+ }
1040
+ department
1041
+ country
1042
+ timezone
1043
+ language {
1044
+ value
1045
+ label
1046
+ }
1047
+ promotionOptIn
1048
+ primaryRetailer {
1049
+ id
1050
+ tradingName
1051
+ }
1052
+ primaryLocation {
1053
+ id
1054
+ type
1055
+ status
1056
+ name
1057
+ }
1058
+ roles {
1059
+ role {
1060
+ id
1061
+ name
1062
+ permissions {
1063
+ name
1064
+ }
1065
+ }
1066
+ }
1067
+ apps {
1068
+ id
1069
+ name
1070
+ version {
1071
+ major
1072
+ minor
1073
+ patch
1074
+ }
1075
+ }
1076
+ }
1077
+ }
1078
+ `;
1079
+ return { data: await client.request(query) };
1080
+ },
1081
+ examplePayload: getCurrentUserExamplePayload
1082
+ })
1083
+ };
1084
+ //#endregion
1085
+ //#region src/actions/products/index.ts
1086
+ var products_default = { createProduct: (0, _prismatic_io_spectral.action)({
1087
+ display: {
1088
+ label: "Create Product",
1089
+ description: "Create a new standard product"
1090
+ },
1091
+ inputs: createProductInputs,
1092
+ outputSchema: (0, _prismatic_io_spectral.outputSchema)({
1093
+ type: "actionOutput",
1094
+ schema: createProductOutputSchema
1095
+ }),
1096
+ performSafety: "notAllowed",
1097
+ perform: async (context, params) => {
1098
+ const client = await createFluentClient(params.connection, context.debug.enabled, context.logger);
1099
+ const query = graphql_request.gql`
1100
+ mutation createProduct(
1101
+ $productCatalogueRef: String!
1102
+ $productRef: String!
1103
+ $productType: String!
1104
+ $productName: String!
1105
+ $productSummary: String!
1106
+ $gtin: String!
1107
+ $priceCurrency: String!
1108
+ $priceValue: Float!
1109
+ ) {
1110
+ createStandardProduct(
1111
+ input: {
1112
+ ref: $productRef
1113
+ catalogue: { ref: $productCatalogueRef }
1114
+ type: $productType
1115
+ name: $productName
1116
+ summary: $productSummary
1117
+ gtin: $gtin
1118
+ prices: [
1119
+ { currency: $priceCurrency, type: "RRP", value: $priceValue }
1120
+ ]
1121
+ }
1122
+ ) {
1123
+ id
1124
+ ref
1125
+ }
1126
+ }
1127
+ `;
1128
+ const variables = {
1129
+ productCatalogueRef: params.productCatalogueRef,
1130
+ productRef: params.productRef,
1131
+ productType: params.productType,
1132
+ productName: params.productName,
1133
+ productSummary: params.productSummary,
1134
+ gtin: params.gtin,
1135
+ priceCurrency: params.priceCurrency,
1136
+ priceValue: params.priceValue
1137
+ };
1138
+ return { data: await client.request(query, variables) };
1139
+ },
1140
+ examplePerform: async () => createProductExamplePayload,
1141
+ examplePayload: createProductExamplePayload
1142
+ }) };
1143
+ //#endregion
1144
+ //#region src/actions/index.ts
1145
+ var actions_default = {
1146
+ ...customers_default,
1147
+ ...misc_default,
1148
+ ...products_default
1149
+ };
1150
+ //#endregion
1151
+ //#region src/triggers/index.ts
1152
+ var triggers_default = { pollChangesTrigger: (0, _prismatic_io_spectral.pollingTrigger)({
1153
+ display: {
1154
+ label: "New and Updated Records",
1155
+ description: "Retrieves existing and ongoing orders from Fluent Commerce. Load history once, check for changes on a schedule, or both."
1156
+ },
1157
+ examplePayload: pollChangesTriggerExamplePayload,
1158
+ inputs: pollChangesInputs,
1159
+ triggerResolverSupport: "valid",
1160
+ batchConfig: { batchSize: 50 },
1161
+ triggerResolver: {
1162
+ resolveItems: (_context, { payload }) => resolveFluentOrderChanges(payload.body.data),
1163
+ getNextPaginationState: (_context, { payload }) => payload.paginationState ?? null
1164
+ },
1165
+ perform: async (context, payload, params) => {
1166
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1167
+ const pollState = context.polling.getState() ?? {};
1168
+ const incoming = payload.paginationState;
1169
+ const lastPolledAt = pollState.lastPolledAt || params.lookBackDate || now;
1170
+ const isBackfill = pollState.backfillActive === true || !pollState.lastPolledAt && Boolean(params.lookBackDate);
1171
+ const showNew = isBackfill || params.showNewRecords !== false;
1172
+ const showUpdated = isBackfill || params.showUpdatedRecords !== false;
1173
+ const windowTo = incoming?.windowTo ?? pollState.windowTo ?? now;
1174
+ const cursor = incoming?.after ?? pollState.after ?? null;
1175
+ const isBatching = context.batch?.enabled === true;
1176
+ const { records, truncated, after } = await fetchFluentOrdersInWindow(params.connection, {
1177
+ from: lastPolledAt,
1178
+ to: windowTo,
1179
+ after: cursor
1180
+ }, params.retailerId, isBatching ? 1 : 20);
1181
+ const lastPolledAtDate = new Date(lastPolledAt);
1182
+ const created = [];
1183
+ const updated = [];
1184
+ for (const record of records) {
1185
+ const createValue = record.createdOn;
1186
+ const createdAtDate = typeof createValue === "string" ? new Date(createValue) : null;
1187
+ const isNew = createdAtDate !== null && createdAtDate > lastPolledAtDate;
1188
+ if (isNew && showNew) created.push(record);
1189
+ else if (!isNew && showUpdated) updated.push(record);
1190
+ }
1191
+ if (truncated) {
1192
+ context.polling.setState({
1193
+ lastPolledAt,
1194
+ windowTo,
1195
+ after,
1196
+ ...isBackfill ? { backfillActive: true } : {}
1197
+ });
1198
+ if (!isBatching) context.logger.warn(`Polling truncated at the page cap for Fluent orders. The next poll resumes the window ${lastPolledAt} to ${windowTo} from the stored cursor.`);
1199
+ } else context.polling.setState({ lastPolledAt: windowTo });
1200
+ if (context.debug.enabled) context.logger.debug(`Polled Fluent orders: ${records.length} fetched, ${created.length} created, ${updated.length} updated, truncated=${truncated}`);
1201
+ const nextCursor = truncated && after ? {
1202
+ windowTo,
1203
+ after
1204
+ } : null;
1205
+ const totalMatched = created.length + updated.length;
1206
+ return {
1207
+ payload: {
1208
+ ...payload,
1209
+ paginationState: nextCursor ?? void 0,
1210
+ body: { data: {
1211
+ created,
1212
+ updated
1213
+ } }
1214
+ },
1215
+ polledNoChanges: totalMatched === 0 && !incoming && (nextCursor === null || !isBatching)
1216
+ };
1217
+ }
1218
+ }) };
1219
+ //#endregion
1220
+ //#region src/index.ts
1221
+ var src_default = (0, _prismatic_io_spectral.component)({
1222
+ key: "fluent-commerce",
1223
+ documentationUrl: "https://prismatic.io/docs/components/fluent-commerce/",
1224
+ public: true,
1225
+ display: {
1226
+ label: "Fluent Commerce",
1227
+ description: "Manage orders within Fluent Commerce",
1228
+ iconPath: "icon.png",
1229
+ category: "Application Connectors"
1230
+ },
1231
+ actions: actions_default,
1232
+ connections: connections_default,
1233
+ triggers: triggers_default,
1234
+ hooks: { error: _prismatic_io_spectral_http.handleErrors }
1235
+ });
1236
+ //#endregion
1237
+ //#region npm-dist/.entry.ts
1238
+ var _entry_default = (0, _prismatic_io_spectral.callableComponent)(src_default);
1239
+ //#endregion
1240
+ module.exports = _entry_default;