@reactionary/provider-commercetools 0.0.80 → 0.0.82

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/core/client.js CHANGED
@@ -115,6 +115,7 @@ class CommercetoolsClient {
115
115
  await this.cache.set({ token: "", refreshToken: "", expirationTime: 0 });
116
116
  return AnonymousIdentitySchema.parse({});
117
117
  }
118
+ // FIXME: This can fail if the short-lived access token has expired. In other words, probably missing a token refresh.
118
119
  async introspect() {
119
120
  const session = await this.cache.get();
120
121
  if (!session || !session.token) {
@@ -27,31 +27,31 @@ function withCommercetoolsCapabilities(configuration, capabilities) {
27
27
  const caps = CommercetoolsCapabilitiesSchema.parse(capabilities);
28
28
  const commercetoolsClient = new CommercetoolsClient(config, context);
29
29
  if (caps.product) {
30
- client.product = new CommercetoolsProductProvider(config, ProductSchema, cache, context, commercetoolsClient);
30
+ client.product = new CommercetoolsProductProvider(config, cache, context, commercetoolsClient);
31
31
  }
32
32
  if (caps.profile) {
33
- client.profile = new CommercetoolsProfileProvider(config, ProfileSchema, cache, context, commercetoolsClient);
33
+ client.profile = new CommercetoolsProfileProvider(config, cache, context, commercetoolsClient);
34
34
  }
35
35
  if (caps.productSearch) {
36
- client.productSearch = new CommercetoolsSearchProvider(config, ProductSearchResultItemSchema, cache, context, commercetoolsClient);
36
+ client.productSearch = new CommercetoolsSearchProvider(config, cache, context, commercetoolsClient);
37
37
  }
38
38
  if (caps.identity) {
39
- client.identity = new CommercetoolsIdentityProvider(config, IdentitySchema, cache, context, commercetoolsClient);
39
+ client.identity = new CommercetoolsIdentityProvider(config, cache, context, commercetoolsClient);
40
40
  }
41
41
  if (caps.cart) {
42
- client.cart = new CommercetoolsCartProvider(config, CartSchema, cache, context, commercetoolsClient);
42
+ client.cart = new CommercetoolsCartProvider(config, cache, context, commercetoolsClient);
43
43
  }
44
44
  if (caps.inventory) {
45
- client.inventory = new CommercetoolsInventoryProvider(config, InventorySchema, cache, context, commercetoolsClient);
45
+ client.inventory = new CommercetoolsInventoryProvider(config, cache, context, commercetoolsClient);
46
46
  }
47
47
  if (caps.price) {
48
- client.price = new CommercetoolsPriceProvider(config, PriceSchema, cache, context, commercetoolsClient);
48
+ client.price = new CommercetoolsPriceProvider(config, cache, context, commercetoolsClient);
49
49
  }
50
50
  if (caps.category) {
51
- client.category = new CommercetoolsCategoryProvider(config, CategorySchema, cache, context, commercetoolsClient);
51
+ client.category = new CommercetoolsCategoryProvider(config, cache, context, commercetoolsClient);
52
52
  }
53
53
  if (caps.checkout) {
54
- client.checkout = new CommercetoolsCheckoutProvider(config, CheckoutSchema, cache, context, commercetoolsClient);
54
+ client.checkout = new CommercetoolsCheckoutProvider(config, cache, context, commercetoolsClient);
55
55
  }
56
56
  return client;
57
57
  };
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@reactionary/provider-commercetools",
3
- "version": "0.0.80",
3
+ "version": "0.0.82",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
- "@reactionary/core": "0.0.80",
7
+ "@reactionary/core": "0.0.82",
8
8
  "debug": "^4.4.3",
9
9
  "zod": "4.1.9",
10
10
  "@commercetools/ts-client": "^4.2.1",
@@ -9,14 +9,25 @@ var __decorateClass = (decorators, target, key, kind) => {
9
9
  __defProp(target, key, result);
10
10
  return result;
11
11
  };
12
- import { CartIdentifierSchema, CartItemSchema, CartMutationApplyCouponSchema, CartMutationChangeCurrencySchema, CartMutationCheckoutSchema, CartMutationDeleteCartSchema, CartMutationItemAddSchema, CartMutationItemQuantityChangeSchema, CartMutationItemRemoveSchema, CartMutationRemoveCouponSchema, CartMutationSetBillingAddressSchema, CartMutationSetShippingInfoSchema, CartProvider, CartQueryByIdSchema, CartSchema, OrderIdentifierSchema, Reactionary } from "@reactionary/core";
13
12
  import {
14
- CommercetoolsCartIdentifierSchema,
15
- CommercetoolsOrderIdentifierSchema
16
- } from "../schema/commercetools.schema.js";
13
+ CartIdentifierSchema,
14
+ CartItemSchema,
15
+ CartMutationApplyCouponSchema,
16
+ CartMutationChangeCurrencySchema,
17
+ CartMutationDeleteCartSchema,
18
+ CartMutationItemAddSchema,
19
+ CartMutationItemQuantityChangeSchema,
20
+ CartMutationItemRemoveSchema,
21
+ CartMutationRemoveCouponSchema,
22
+ CartProvider,
23
+ CartQueryByIdSchema,
24
+ CartSchema,
25
+ Reactionary
26
+ } from "@reactionary/core";
27
+ import { CommercetoolsCartIdentifierSchema } from "../schema/commercetools.schema.js";
17
28
  class CommercetoolsCartProvider extends CartProvider {
18
- constructor(config, schema, cache, context, client) {
19
- super(schema, cache, context);
29
+ constructor(config, cache, context, client) {
30
+ super(cache, context);
20
31
  this.config = config;
21
32
  this.client = client;
22
33
  }
@@ -215,13 +226,10 @@ class CommercetoolsCartProvider extends CartProvider {
215
226
  };
216
227
  }
217
228
  parseSingle(remote) {
218
- const result = this.newModel();
219
- result.identifier = CommercetoolsCartIdentifierSchema.parse({
229
+ const identifier = {
220
230
  key: remote.id,
221
231
  version: remote.version || 0
222
- });
223
- result.name = remote.custom?.fields["name"] || "";
224
- result.description = remote.custom?.fields["description"] || "";
232
+ };
225
233
  const grandTotal = remote.totalPrice.centAmount || 0;
226
234
  const shippingTotal = remote.shippingInfo?.price.centAmount || 0;
227
235
  const productTotal = grandTotal - shippingTotal;
@@ -229,7 +237,7 @@ class CommercetoolsCartProvider extends CartProvider {
229
237
  const discountTotal = remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
230
238
  const surchargeTotal = 0;
231
239
  const currency = remote.totalPrice.currencyCode;
232
- result.price = {
240
+ const price = {
233
241
  totalTax: {
234
242
  value: taxTotal / 100,
235
243
  currency
@@ -255,6 +263,7 @@ class CommercetoolsCartProvider extends CartProvider {
255
263
  currency
256
264
  }
257
265
  };
266
+ const items = new Array();
258
267
  for (const remoteItem of remote.lineItems) {
259
268
  const item = CartItemSchema.parse({});
260
269
  item.identifier.key = remoteItem.id;
@@ -283,16 +292,26 @@ class CommercetoolsCartProvider extends CartProvider {
283
292
  currency
284
293
  }
285
294
  };
286
- result.items.push(item);
295
+ items.push(item);
287
296
  }
288
- result.meta = {
289
- cache: {
290
- hit: false,
291
- key: this.generateCacheKeySingle(result.identifier)
297
+ const cart = {
298
+ identifier,
299
+ userId: {
300
+ userId: "???"
301
+ },
302
+ name: remote.custom?.fields["name"] || "",
303
+ description: remote.custom?.fields["description"] || "",
304
+ price,
305
+ meta: {
306
+ cache: {
307
+ hit: false,
308
+ key: this.generateCacheKeySingle(identifier)
309
+ },
310
+ placeholder: false
292
311
  },
293
- placeholder: false
312
+ items
294
313
  };
295
- return this.assert(result);
314
+ return cart;
296
315
  }
297
316
  }
298
317
  __decorateClass([
@@ -18,13 +18,12 @@ import {
18
18
  CategoryQueryForChildCategoriesSchema,
19
19
  CategoryQueryForTopCategoriesSchema,
20
20
  CategorySchema,
21
- createPaginatedResponseSchema,
22
21
  Reactionary
23
22
  } from "@reactionary/core";
24
23
  import z from "zod";
25
24
  class CommercetoolsCategoryProvider extends CategoryProvider {
26
- constructor(config, schema, cache, context, client) {
27
- super(schema, cache, context);
25
+ constructor(config, cache, context, client) {
26
+ super(cache, context);
28
27
  this.config = config;
29
28
  this.client = client;
30
29
  }
@@ -38,9 +37,22 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
38
37
  const response = await client.withKey({ key: payload.id.key }).get().execute();
39
38
  return this.parseSingle(response.body);
40
39
  } catch (error) {
41
- const dummyCategory = this.newModel();
42
- dummyCategory.meta.placeholder = true;
43
- dummyCategory.identifier = { key: payload.id.key };
40
+ const dummyCategory = {
41
+ identifier: {
42
+ key: payload.id.key
43
+ },
44
+ images: [],
45
+ name: "",
46
+ slug: "",
47
+ text: "",
48
+ meta: {
49
+ cache: {
50
+ hit: false,
51
+ key: ""
52
+ },
53
+ placeholder: false
54
+ }
55
+ };
44
56
  return dummyCategory;
45
57
  }
46
58
  }
@@ -67,7 +79,7 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
67
79
  }
68
80
  async getBreadcrumbPathToCategory(payload) {
69
81
  const client = await this.getClient();
70
- const path = [];
82
+ const path = new Array();
71
83
  try {
72
84
  const response = await client.withKey({ key: payload.id.key }).get({
73
85
  queryArgs: {
@@ -122,7 +134,21 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
122
134
  error
123
135
  );
124
136
  }
125
- return createPaginatedResponseSchema(this.schema).parse({});
137
+ const empty = {
138
+ items: [],
139
+ meta: {
140
+ cache: {
141
+ hit: false,
142
+ key: ""
143
+ },
144
+ placeholder: true
145
+ },
146
+ pageNumber: payload.paginationOptions.pageNumber,
147
+ pageSize: payload.paginationOptions.pageSize,
148
+ totalCount: 0,
149
+ totalPages: 0
150
+ };
151
+ return empty;
126
152
  }
127
153
  async findTopCategories(payload) {
128
154
  const client = await this.getClient();
@@ -148,7 +174,21 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
148
174
  } catch (error) {
149
175
  console.error(`Error fetching category top categories:`, error);
150
176
  }
151
- return createPaginatedResponseSchema(this.schema).parse({});
177
+ const empty = {
178
+ items: [],
179
+ meta: {
180
+ cache: {
181
+ hit: false,
182
+ key: ""
183
+ },
184
+ placeholder: true
185
+ },
186
+ pageNumber: payload.paginationOptions.pageNumber,
187
+ pageSize: payload.paginationOptions.pageSize,
188
+ totalCount: 0,
189
+ totalPages: 0
190
+ };
191
+ return empty;
152
192
  }
153
193
  /**
154
194
  * Handler for parsing a response from a remote provider and converting it
@@ -157,30 +197,32 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
157
197
  parseSingle(_body) {
158
198
  const body = _body;
159
199
  const languageContext = this.context.languageContext;
160
- const model = this.newModel();
161
- model.identifier = { key: body.key };
162
- model.name = body.name[languageContext.locale] || "No Name";
163
- model.slug = body.slug ? body.slug[languageContext.locale] || "" : "";
164
- model.text = body.description ? body.description[languageContext.locale] || "" : "";
165
- model.parentCategory = body.parent && body.parent.obj && body.parent.obj?.key ? { key: body.parent.obj.key } : void 0;
166
- model.images = (body.assets || []).filter((asset) => asset.sources.length > 0).filter((x) => x.sources[0].contentType?.startsWith("image/")).map((asset) => {
167
- return {
168
- sourceUrl: asset.sources[0].uri,
169
- altText: asset.description?.[languageContext.locale] || asset.name[languageContext.locale] || "",
170
- height: asset.sources[0].dimensions?.h || 0,
171
- width: asset.sources[0].dimensions?.w || 0
172
- };
173
- });
174
- model.meta = {
175
- cache: { hit: false, key: this.generateCacheKeySingle(model.identifier) },
176
- placeholder: false
200
+ const identifier = { key: body.key };
201
+ const model = {
202
+ identifier,
203
+ name: body.name[languageContext.locale] || "No Name",
204
+ slug: body.slug ? body.slug[languageContext.locale] || "" : "",
205
+ text: body.description ? body.description[languageContext.locale] || "" : "",
206
+ parentCategory: body.parent && body.parent.obj && body.parent.obj?.key ? { key: body.parent.obj.key } : void 0,
207
+ images: (body.assets || []).filter((asset) => asset.sources.length > 0).filter((x) => x.sources[0].contentType?.startsWith("image/")).map((asset) => {
208
+ return {
209
+ sourceUrl: asset.sources[0].uri,
210
+ altText: asset.description?.[languageContext.locale] || asset.name[languageContext.locale] || "",
211
+ height: asset.sources[0].dimensions?.h || 0,
212
+ width: asset.sources[0].dimensions?.w || 0
213
+ };
214
+ }),
215
+ meta: {
216
+ cache: { hit: false, key: this.generateCacheKeySingle(identifier) },
217
+ placeholder: false
218
+ }
177
219
  };
178
- return this.assert(model);
220
+ return model;
179
221
  }
180
222
  parsePaginatedResult(_body) {
181
223
  const body = _body;
182
224
  const items = body.results.map((x) => this.parseSingle(x));
183
- const result = createPaginatedResponseSchema(this.schema).parse({
225
+ const result = {
184
226
  meta: {
185
227
  cache: { hit: false, key: "unknown" },
186
228
  placeholder: false
@@ -190,7 +232,7 @@ class CommercetoolsCategoryProvider extends CategoryProvider {
190
232
  totalCount: body.total || 0,
191
233
  totalPages: Math.ceil((body.total ?? 0) / body.count),
192
234
  items
193
- });
235
+ };
194
236
  return result;
195
237
  }
196
238
  }
@@ -10,7 +10,6 @@ var __decorateClass = (decorators, target, key, kind) => {
10
10
  return result;
11
11
  };
12
12
  import {
13
- AddressSchema,
14
13
  CheckoutItemSchema,
15
14
  CheckoutMutationAddPaymentInstructionSchema,
16
15
  CheckoutMutationFinalizeCheckoutSchema,
@@ -33,8 +32,6 @@ import {
33
32
  } from "@reactionary/core";
34
33
  import z from "zod";
35
34
  import {
36
- CommercetoolsCartIdentifierSchema,
37
- CommercetoolsCheckoutIdentifierSchema
38
35
  } from "../schema/commercetools.schema.js";
39
36
  class CheckoutNotReadyForFinalizationError extends Error {
40
37
  constructor(checkoutIdentifier) {
@@ -46,8 +43,8 @@ class CheckoutNotReadyForFinalizationError extends Error {
46
43
  }
47
44
  }
48
45
  class CommercetoolsCheckoutProvider extends CheckoutProvider {
49
- constructor(config, schema, cache, context, client) {
50
- super(schema, cache, context);
46
+ constructor(config, cache, context, client) {
47
+ super(cache, context);
51
48
  this.config = config;
52
49
  this.client = client;
53
50
  }
@@ -283,7 +280,9 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
283
280
  version: ctId.version
284
281
  }
285
282
  }).execute();
286
- return this.getById({ identifier: payload.checkout });
283
+ return this.getById({
284
+ identifier: payload.checkout
285
+ });
287
286
  }
288
287
  async applyActions(checkout, actions) {
289
288
  const client = await this.getClient();
@@ -318,27 +317,26 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
318
317
  return this.config.paymentMethods || [];
319
318
  }
320
319
  parseSingle(remote) {
321
- const result = this.newModel();
322
- result.identifier = CommercetoolsCheckoutIdentifierSchema.parse({
320
+ const identifier = {
323
321
  key: remote.id,
324
322
  version: remote.version || 0
325
- });
326
- result.name = remote.custom?.fields["name"] || "";
327
- result.description = remote.custom?.fields["description"] || "";
328
- result.originalCartReference = CommercetoolsCartIdentifierSchema.parse({
323
+ };
324
+ const originalCartReference = {
329
325
  key: remote.custom?.fields["commerceToolsCartId"] || "",
330
326
  version: 0
331
- });
327
+ };
328
+ let shippingAddress;
332
329
  if (remote.shippingAddress) {
333
- result.shippingAddress = this.parseAddress(remote.shippingAddress);
330
+ shippingAddress = this.parseAddress(remote.shippingAddress);
334
331
  }
332
+ let billingAddress;
335
333
  if (remote.billingAddress) {
336
- result.billingAddress = this.parseAddress(remote.billingAddress);
334
+ billingAddress = this.parseAddress(remote.billingAddress);
337
335
  }
338
- result.shippingInstruction = this.parseShippingInstruction(remote);
336
+ const paymentInstructions = new Array();
339
337
  for (const p of remote.paymentInfo?.payments || []) {
340
338
  if (p.obj) {
341
- result.paymentInstructions.push(this.parsePaymentInstruction(p.obj));
339
+ paymentInstructions.push(this.parsePaymentInstruction(p.obj));
342
340
  }
343
341
  }
344
342
  const grandTotal = remote.totalPrice.centAmount || 0;
@@ -348,7 +346,7 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
348
346
  const discountTotal = remote.discountOnTotalPrice?.discountedAmount.centAmount || 0;
349
347
  const surchargeTotal = 0;
350
348
  const currency = remote.totalPrice.currencyCode;
351
- result.price = {
349
+ const price = {
352
350
  totalTax: {
353
351
  value: taxTotal / 100,
354
352
  currency
@@ -374,6 +372,7 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
374
372
  currency
375
373
  }
376
374
  };
375
+ const items = new Array();
377
376
  for (const remoteItem of remote.lineItems) {
378
377
  const item = CheckoutItemSchema.parse({});
379
378
  item.identifier.key = remoteItem.id;
@@ -401,29 +400,43 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
401
400
  currency
402
401
  }
403
402
  };
404
- result.items.push(item);
403
+ items.push(item);
405
404
  }
406
- result.readyForFinalization = this.isReadyForFinalization(result);
407
- result.meta = {
408
- cache: {
409
- hit: false,
410
- key: this.generateCacheKeySingle(result.identifier)
405
+ const shippingInstruction = this.parseShippingInstruction(remote);
406
+ const readyForFinalization = this.isReadyForFinalization(price, paymentInstructions, billingAddress, shippingAddress, shippingInstruction);
407
+ const result = {
408
+ identifier,
409
+ originalCartReference,
410
+ name: remote.custom?.fields["name"] || "",
411
+ description: remote.custom?.fields["description"] || "",
412
+ readyForFinalization,
413
+ meta: {
414
+ cache: {
415
+ hit: false,
416
+ key: this.generateCacheKeySingle(identifier)
417
+ },
418
+ placeholder: false
411
419
  },
412
- placeholder: false
420
+ billingAddress,
421
+ shippingAddress,
422
+ shippingInstruction,
423
+ paymentInstructions,
424
+ items,
425
+ price
413
426
  };
414
- return this.assert(result);
427
+ return result;
415
428
  }
416
- isReadyForFinalization(checkout) {
417
- if (!checkout.billingAddress)
429
+ isReadyForFinalization(price, paymentInstructions, billingAddress, shippingAddress, shippingInstruction) {
430
+ if (!billingAddress)
418
431
  return false;
419
- if (!checkout.shippingInstruction)
432
+ if (!shippingInstruction)
420
433
  return false;
421
- if (!checkout.shippingAddress && !checkout.shippingInstruction.pickupPoint)
434
+ if (!shippingAddress && !shippingInstruction.pickupPoint)
422
435
  return false;
423
- if (checkout.paymentInstructions.length === 0)
436
+ if (paymentInstructions.length === 0)
424
437
  return false;
425
- const authorizedPayments = checkout.paymentInstructions.filter((pi) => pi.status === "authorized").map((x) => x.amount.value).reduce((a, b) => a + b, 0);
426
- if (checkout.price.grandTotal.value !== authorizedPayments)
438
+ const authorizedPayments = paymentInstructions.filter((pi) => pi.status === "authorized").map((x) => x.amount.value).reduce((a, b) => a + b, 0);
439
+ if (price.grandTotal.value !== authorizedPayments)
427
440
  return false;
428
441
  return true;
429
442
  }
@@ -459,15 +472,26 @@ class CommercetoolsCheckoutProvider extends CheckoutProvider {
459
472
  return PaymentInstructionSchema.parse(newModel);
460
473
  }
461
474
  parseAddress(remote) {
462
- return AddressSchema.parse({
475
+ return {
463
476
  countryCode: remote.country || "",
464
477
  firstName: remote.firstName || "",
465
478
  lastName: remote.lastName || "",
466
479
  streetAddress: remote.streetName || "",
467
480
  streetNumber: remote.streetNumber || "",
468
481
  postalCode: remote.postalCode || "",
469
- city: remote.city || ""
470
- });
482
+ city: remote.city || "",
483
+ identifier: {
484
+ nickName: ""
485
+ },
486
+ meta: {
487
+ cache: {
488
+ hit: false,
489
+ key: ""
490
+ },
491
+ placeholder: false
492
+ },
493
+ region: ""
494
+ };
471
495
  }
472
496
  parseShippingInstruction(remote) {
473
497
  if (!remote.shippingInfo)
@@ -18,8 +18,8 @@ import {
18
18
  IdentityMutationLoginSchema
19
19
  } from "@reactionary/core";
20
20
  class CommercetoolsIdentityProvider extends IdentityProvider {
21
- constructor(config, schema, cache, context, client) {
22
- super(schema, cache, context);
21
+ constructor(config, cache, context, client) {
22
+ super(cache, context);
23
23
  this.config = config;
24
24
  this.client = client;
25
25
  }
@@ -11,8 +11,8 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  };
12
12
  import { InventoryProvider, InventoryQueryBySKUSchema, InventorySchema, Reactionary } from "@reactionary/core";
13
13
  class CommercetoolsInventoryProvider extends InventoryProvider {
14
- constructor(config, schema, cache, context, client) {
15
- super(schema, cache, context);
14
+ constructor(config, cache, context, client) {
15
+ super(cache, context);
16
16
  this.config = config;
17
17
  this.client = client;
18
18
  }
@@ -47,27 +47,31 @@ class CommercetoolsInventoryProvider extends InventoryProvider {
47
47
  }
48
48
  }
49
49
  parseSingle(body) {
50
- const model = this.newModel();
51
- model.identifier = {
50
+ const identifier = {
52
51
  variant: { sku: body.sku || "" },
53
52
  fulfillmentCenter: {
54
53
  key: body.supplyChannel?.obj?.key || ""
55
54
  }
56
55
  };
57
- model.quantity = body.availableQuantity || 0;
58
- if (model.quantity > 0) {
59
- model.status = "inStock";
60
- } else {
61
- model.status = "outOfStock";
56
+ const quantity = body.availableQuantity || 0;
57
+ let status = "outOfStock";
58
+ if (quantity > 0) {
59
+ status = "inStock";
62
60
  }
63
- model.meta = {
61
+ const meta = {
64
62
  cache: {
65
63
  hit: false,
66
- key: this.generateCacheKeySingle(model.identifier)
64
+ key: this.generateCacheKeySingle(identifier)
67
65
  },
68
66
  placeholder: false
69
67
  };
70
- return this.assert(model);
68
+ const result = {
69
+ identifier,
70
+ quantity,
71
+ status,
72
+ meta
73
+ };
74
+ return result;
71
75
  }
72
76
  }
73
77
  __decorateClass([