@cimplify/sdk 0.100.2 → 0.100.4

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.
Files changed (55) hide show
  1. package/README.md +17 -0
  2. package/dist/advanced.d.mts +1 -1
  3. package/dist/advanced.d.ts +1 -1
  4. package/dist/advanced.js +20 -20
  5. package/dist/advanced.mjs +1 -1
  6. package/dist/{chunk-6JEKKL3M.js → chunk-3HU5I5VG.js} +23 -4
  7. package/dist/{chunk-YWNJJO2U.mjs → chunk-HSDQWJLA.mjs} +2 -2
  8. package/dist/{chunk-IJI7KMTG.js → chunk-JEVCHTKZ.js} +256 -74
  9. package/dist/{chunk-QRBBSIAY.js → chunk-LMD7B33E.js} +4 -4
  10. package/dist/{chunk-IFAQLFAJ.js → chunk-PNTINRAU.js} +33 -3
  11. package/dist/{chunk-B2YOCOLH.mjs → chunk-RQPXLXB2.mjs} +33 -3
  12. package/dist/{chunk-PJUXAUM2.mjs → chunk-RWR7JF7F.mjs} +210 -28
  13. package/dist/{chunk-TIQLOH2B.mjs → chunk-Z7M6GAHS.mjs} +23 -4
  14. package/dist/{client-D8XcrONA.d.mts → client-BwRAAk4y.d.mts} +26 -2
  15. package/dist/{client-CgXkRu2o.d.ts → client-CPcZIrjC.d.ts} +2 -2
  16. package/dist/{client-LPg_AUUr.d.ts → client-CrPglBBz.d.ts} +26 -2
  17. package/dist/{client-C6wb92AD.d.mts → client-DGrvLiJv.d.mts} +2 -2
  18. package/dist/index.d.mts +2 -2
  19. package/dist/index.d.ts +2 -2
  20. package/dist/index.js +69 -69
  21. package/dist/index.mjs +3 -3
  22. package/dist/lint-rules.json +1 -0
  23. package/dist/lint.d.mts +537 -0
  24. package/dist/lint.d.ts +537 -0
  25. package/dist/lint.js +540 -0
  26. package/dist/lint.mjs +524 -0
  27. package/dist/mock/cli.mjs +33 -3
  28. package/dist/mock/library.js +33 -3
  29. package/dist/mock/library.mjs +33 -3
  30. package/dist/mock/msw.js +33 -3
  31. package/dist/mock/msw.mjs +33 -3
  32. package/dist/react.d.mts +10 -5
  33. package/dist/react.d.ts +10 -5
  34. package/dist/react.js +40 -35
  35. package/dist/react.mjs +14 -9
  36. package/dist/{server--RyVAfPN.d.mts → server-DRAW2OOX.d.mts} +7 -4
  37. package/dist/{server-CNyy47HL.d.ts → server-zyrpzJVn.d.ts} +7 -4
  38. package/dist/server.d.mts +2 -2
  39. package/dist/server.d.ts +2 -2
  40. package/dist/server.js +7 -7
  41. package/dist/server.mjs +2 -2
  42. package/dist/styles.css +1 -1
  43. package/dist/testing/msw.d.mts +1 -1
  44. package/dist/testing/msw.d.ts +1 -1
  45. package/dist/testing/msw.js +2 -2
  46. package/dist/testing/msw.mjs +1 -1
  47. package/dist/testing/suite.d.mts +4 -4
  48. package/dist/testing/suite.d.ts +4 -4
  49. package/dist/testing/suite.js +23 -23
  50. package/dist/testing/suite.mjs +4 -4
  51. package/dist/testing.d.mts +3 -3
  52. package/dist/testing.d.ts +3 -3
  53. package/dist/testing.js +79 -79
  54. package/dist/testing.mjs +5 -5
  55. package/package.json +10 -2
package/dist/lint.mjs ADDED
@@ -0,0 +1,524 @@
1
+ import './chunk-3G6RQLXK.mjs';
2
+ import { RE2JS } from 're2js';
3
+
4
+ // src/lint/types.ts
5
+ var LINT_RULE_SET_SCHEMA_VERSION = 1;
6
+ var MAX_LINT_RULE_MANIFEST_BYTES = 256 * 1024;
7
+ var MAX_RULES = 64;
8
+ var MAX_ARRAY_ITEMS = 64;
9
+ var MAX_TOTAL_REGEX_PATTERNS = 64;
10
+ var MAX_TOTAL_RULE_TERMS = 512;
11
+ var MAX_PATH_SEGMENTS = 8;
12
+ var MAX_NAME_LENGTH = 160;
13
+ var MAX_MESSAGE_LENGTH = 512;
14
+ var MAX_HELP_LENGTH = 1024;
15
+ var MAX_PATTERN_LENGTH = 512;
16
+ var MAX_MODULE_LENGTH = 256;
17
+ var MAX_IDENTIFIER_LENGTH = 128;
18
+ var RULE_ID_PATTERN = /^[a-z][a-z0-9-]*\/[a-z][a-z0-9-]*$/;
19
+ var JAVASCRIPT_IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
20
+ var JSX_COMPONENT_IDENTIFIER_PATTERN = /^[A-Z][A-Za-z0-9_$]*$/;
21
+ var NUMERIC_OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "<", "<=", ">", ">="]);
22
+ var PRIMITIVE_KINDS = /* @__PURE__ */ new Set([
23
+ "required-result-check",
24
+ "required-wrapper-call",
25
+ "banned-import",
26
+ "banned-call-argument",
27
+ "banned-jsx-element",
28
+ "banned-classname-pattern"
29
+ ]);
30
+ function isRecord(value) {
31
+ return value !== null && typeof value === "object" && !Array.isArray(value);
32
+ }
33
+ function expectRecord(value, label) {
34
+ if (!isRecord(value)) throw new TypeError(`${label} must be an object`);
35
+ return value;
36
+ }
37
+ function expectOnlyKeys(value, label, allowed, required) {
38
+ const allowedSet = new Set(allowed);
39
+ for (const key of Object.keys(value)) {
40
+ if (!allowedSet.has(key)) throw new TypeError(`${label} has unknown property ${key}`);
41
+ }
42
+ for (const key of required) {
43
+ if (!(key in value)) throw new TypeError(`${label} is missing ${key}`);
44
+ }
45
+ }
46
+ function expectString(value, label, maxLength) {
47
+ if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
48
+ throw new TypeError(`${label} must be a non-empty string of at most ${maxLength} characters`);
49
+ }
50
+ if (value.includes("\0")) throw new TypeError(`${label} cannot contain NUL`);
51
+ return value;
52
+ }
53
+ function expectBoolean(value, label) {
54
+ if (typeof value !== "boolean") throw new TypeError(`${label} must be boolean`);
55
+ return value;
56
+ }
57
+ function expectArray(value, label, options = {}) {
58
+ if (!Array.isArray(value) || value.length > MAX_ARRAY_ITEMS) {
59
+ throw new TypeError(`${label} must be an array of at most ${MAX_ARRAY_ITEMS} items`);
60
+ }
61
+ if (options.nonEmpty && value.length === 0) throw new TypeError(`${label} cannot be empty`);
62
+ return value;
63
+ }
64
+ function expectStringArray(value, label, maxLength = MAX_IDENTIFIER_LENGTH, options = {}) {
65
+ return expectArray(value, label, options).map(
66
+ (item, index) => expectString(item, `${label}[${index}]`, maxLength)
67
+ );
68
+ }
69
+ function expectIntegerArray(value, label) {
70
+ return expectArray(value, label, { nonEmpty: true }).map((item, index) => {
71
+ if (typeof item !== "number" || !Number.isSafeInteger(item) || item < 0 || item > 32) {
72
+ throw new TypeError(`${label}[${index}] must be an integer between 0 and 32`);
73
+ }
74
+ return item;
75
+ });
76
+ }
77
+ function validateSafePattern(value, label) {
78
+ const pattern = expectString(value, label, MAX_PATTERN_LENGTH);
79
+ try {
80
+ RE2JS.compile(pattern);
81
+ } catch {
82
+ throw new TypeError(`${label} is not a valid linear-time regular expression`);
83
+ }
84
+ return pattern;
85
+ }
86
+ function expectIdentifier(value, label, pattern = JAVASCRIPT_IDENTIFIER_PATTERN) {
87
+ const identifier = expectString(value, label, MAX_IDENTIFIER_LENGTH);
88
+ if (!pattern.test(identifier)) throw new TypeError(`${label} must be a safe identifier`);
89
+ return identifier;
90
+ }
91
+ function validateImportBindings(value, label) {
92
+ for (const [index, item] of expectArray(value, label, { nonEmpty: true }).entries()) {
93
+ const binding = expectRecord(item, `${label}[${index}]`);
94
+ expectOnlyKeys(binding, `${label}[${index}]`, ["source", "imported"], ["source", "imported"]);
95
+ expectString(binding.source, `${label}[${index}].source`, MAX_MODULE_LENGTH);
96
+ expectStringArray(binding.imported, `${label}[${index}].imported`, MAX_IDENTIFIER_LENGTH, {
97
+ nonEmpty: true
98
+ });
99
+ }
100
+ }
101
+ function validateImportSources(value, label) {
102
+ for (const [index, item] of expectArray(value, label, { nonEmpty: true }).entries()) {
103
+ const source = expectRecord(item, `${label}[${index}]`);
104
+ expectOnlyKeys(source, `${label}[${index}]`, ["value", "match"], ["value", "match"]);
105
+ expectString(source.value, `${label}[${index}].value`, MAX_MODULE_LENGTH);
106
+ if (source.match !== "exact" && source.match !== "prefix") {
107
+ throw new TypeError(`${label}[${index}].match must be exact or prefix`);
108
+ }
109
+ }
110
+ }
111
+ function validatePrimitive(value, label) {
112
+ const primitive = expectRecord(value, label);
113
+ if (!PRIMITIVE_KINDS.has(primitive.kind)) {
114
+ throw new TypeError(`${label}.kind is unsupported`);
115
+ }
116
+ switch (primitive.kind) {
117
+ case "required-result-check":
118
+ expectOnlyKeys(
119
+ primitive,
120
+ label,
121
+ ["kind", "factories", "guardProperty", "valueProperty"],
122
+ ["kind", "factories", "guardProperty", "valueProperty"]
123
+ );
124
+ validateImportBindings(primitive.factories, `${label}.factories`);
125
+ expectString(primitive.guardProperty, `${label}.guardProperty`, MAX_IDENTIFIER_LENGTH);
126
+ expectString(primitive.valueProperty, `${label}.valueProperty`, MAX_IDENTIFIER_LENGTH);
127
+ break;
128
+ case "required-wrapper-call": {
129
+ expectOnlyKeys(
130
+ primitive,
131
+ label,
132
+ ["kind", "context", "activationImports", "subjectNamePattern", "wrapper", "operators"],
133
+ ["kind", "context", "activationImports", "subjectNamePattern", "wrapper"]
134
+ );
135
+ if (primitive.context !== "jsx-child" && primitive.context !== "numeric-operation") {
136
+ throw new TypeError(`${label}.context is unsupported`);
137
+ }
138
+ validateImportSources(primitive.activationImports, `${label}.activationImports`);
139
+ validateSafePattern(primitive.subjectNamePattern, `${label}.subjectNamePattern`);
140
+ const wrapper = expectRecord(primitive.wrapper, `${label}.wrapper`);
141
+ if (wrapper.syntax === "jsx") {
142
+ expectOnlyKeys(
143
+ wrapper,
144
+ `${label}.wrapper`,
145
+ ["syntax", "source", "imported", "prop"],
146
+ ["syntax", "source", "imported", "prop"]
147
+ );
148
+ if (primitive.context !== "jsx-child") {
149
+ throw new TypeError(`${label} uses a JSX wrapper outside JSX context`);
150
+ }
151
+ expectString(wrapper.source, `${label}.wrapper.source`, MAX_MODULE_LENGTH);
152
+ expectIdentifier(
153
+ wrapper.imported,
154
+ `${label}.wrapper.imported`,
155
+ JSX_COMPONENT_IDENTIFIER_PATTERN
156
+ );
157
+ expectIdentifier(wrapper.prop, `${label}.wrapper.prop`);
158
+ } else if (wrapper.syntax === "call") {
159
+ expectOnlyKeys(wrapper, `${label}.wrapper`, ["syntax", "imports"], ["syntax", "imports"]);
160
+ if (primitive.context !== "numeric-operation") {
161
+ throw new TypeError(`${label} uses a call wrapper outside numeric context`);
162
+ }
163
+ validateImportBindings(wrapper.imports, `${label}.wrapper.imports`);
164
+ } else {
165
+ throw new TypeError(`${label}.wrapper.syntax is unsupported`);
166
+ }
167
+ if (primitive.operators !== void 0) {
168
+ const operators = expectStringArray(primitive.operators, `${label}.operators`, 4, {
169
+ nonEmpty: true
170
+ });
171
+ if (operators.some((operator) => !NUMERIC_OPERATORS.has(operator))) {
172
+ throw new TypeError(`${label}.operators contains an unsupported operator`);
173
+ }
174
+ }
175
+ break;
176
+ }
177
+ case "banned-import":
178
+ expectOnlyKeys(primitive, label, ["kind", "sources"], ["kind", "sources"]);
179
+ validateImportSources(primitive.sources, `${label}.sources`);
180
+ break;
181
+ case "banned-call-argument":
182
+ expectOnlyKeys(
183
+ primitive,
184
+ label,
185
+ [
186
+ "kind",
187
+ "callees",
188
+ "globalCalleesOnly",
189
+ "argumentIndexes",
190
+ "objectPaths",
191
+ "caseInsensitive"
192
+ ],
193
+ ["kind", "callees", "argumentIndexes", "objectPaths"]
194
+ );
195
+ expectStringArray(primitive.callees, `${label}.callees`, MAX_IDENTIFIER_LENGTH, {
196
+ nonEmpty: true
197
+ });
198
+ if (primitive.globalCalleesOnly !== void 0) {
199
+ expectBoolean(primitive.globalCalleesOnly, `${label}.globalCalleesOnly`);
200
+ }
201
+ expectIntegerArray(primitive.argumentIndexes, `${label}.argumentIndexes`);
202
+ for (const [index, item] of expectArray(primitive.objectPaths, `${label}.objectPaths`, {
203
+ nonEmpty: true
204
+ }).entries()) {
205
+ const segments = expectStringArray(
206
+ item,
207
+ `${label}.objectPaths[${index}]`,
208
+ MAX_IDENTIFIER_LENGTH,
209
+ { nonEmpty: true }
210
+ );
211
+ if (segments.length > MAX_PATH_SEGMENTS) {
212
+ throw new TypeError(
213
+ `${label}.objectPaths[${index}] exceeds ${MAX_PATH_SEGMENTS} segments`
214
+ );
215
+ }
216
+ }
217
+ if (primitive.caseInsensitive !== void 0) {
218
+ expectBoolean(primitive.caseInsensitive, `${label}.caseInsensitive`);
219
+ }
220
+ break;
221
+ case "banned-jsx-element":
222
+ expectOnlyKeys(primitive, label, ["kind", "elements"], ["kind", "elements"]);
223
+ expectStringArray(primitive.elements, `${label}.elements`, MAX_IDENTIFIER_LENGTH, {
224
+ nonEmpty: true
225
+ });
226
+ break;
227
+ case "banned-classname-pattern":
228
+ expectOnlyKeys(primitive, label, ["kind", "patterns", "replacements"], ["kind", "patterns"]);
229
+ for (const [index, pattern] of expectArray(primitive.patterns, `${label}.patterns`, {
230
+ nonEmpty: true
231
+ }).entries()) {
232
+ validateSafePattern(pattern, `${label}.patterns[${index}]`);
233
+ }
234
+ if (primitive.replacements !== void 0) {
235
+ for (const [index, item] of expectArray(
236
+ primitive.replacements,
237
+ `${label}.replacements`
238
+ ).entries()) {
239
+ const replacement = expectRecord(item, `${label}.replacements[${index}]`);
240
+ expectOnlyKeys(
241
+ replacement,
242
+ `${label}.replacements[${index}]`,
243
+ ["from", "to"],
244
+ ["from", "to"]
245
+ );
246
+ expectString(replacement.from, `${label}.replacements[${index}].from`, 256);
247
+ expectString(replacement.to, `${label}.replacements[${index}].to`, 256);
248
+ }
249
+ }
250
+ break;
251
+ default:
252
+ throw new TypeError(`${label}.kind is unsupported`);
253
+ }
254
+ return primitive;
255
+ }
256
+ function validateFix(value, label, primitive) {
257
+ const fix = expectRecord(value, label);
258
+ expectOnlyKeys(fix, label, ["kind"], ["kind"]);
259
+ if (fix.kind === "wrap-jsx-expression") {
260
+ if (primitive.kind !== "required-wrapper-call" || primitive.context !== "jsx-child" || primitive.wrapper.syntax !== "jsx") {
261
+ throw new TypeError(`${label} is incompatible with its primitive`);
262
+ }
263
+ } else if (fix.kind === "replace-classname") {
264
+ if (primitive.kind !== "banned-classname-pattern") {
265
+ throw new TypeError(`${label} is incompatible with its primitive`);
266
+ }
267
+ } else if (fix.kind === "remove-object-property") {
268
+ if (primitive.kind !== "banned-call-argument") {
269
+ throw new TypeError(`${label} is incompatible with its primitive`);
270
+ }
271
+ } else {
272
+ throw new TypeError(`${label}.kind is unsupported`);
273
+ }
274
+ return fix;
275
+ }
276
+ function validatedRule(value, label) {
277
+ const rule = expectRecord(value, label);
278
+ expectOnlyKeys(
279
+ rule,
280
+ label,
281
+ ["id", "severity", "message", "help", "primitive", "fix"],
282
+ ["id", "severity", "message", "help", "primitive"]
283
+ );
284
+ const id = expectString(rule.id, `${label}.id`, MAX_IDENTIFIER_LENGTH);
285
+ if (!RULE_ID_PATTERN.test(id)) throw new TypeError(`${label}.id is invalid`);
286
+ if (rule.severity !== "error" && rule.severity !== "warning") {
287
+ throw new TypeError(`${label}.severity must be error or warning`);
288
+ }
289
+ expectString(rule.message, `${label}.message`, MAX_MESSAGE_LENGTH);
290
+ expectString(rule.help, `${label}.help`, MAX_HELP_LENGTH);
291
+ const primitive = validatePrimitive(rule.primitive, `${label}.primitive`);
292
+ if (rule.fix !== void 0) validateFix(rule.fix, `${label}.fix`, primitive);
293
+ return rule;
294
+ }
295
+ function deepFreeze(value, seen = /* @__PURE__ */ new WeakSet()) {
296
+ if (value === null || typeof value !== "object" || seen.has(value)) return value;
297
+ seen.add(value);
298
+ for (const nested of Object.values(value)) deepFreeze(nested, seen);
299
+ return Object.freeze(value);
300
+ }
301
+ function validateLintRule(value) {
302
+ return deepFreeze(validatedRule(value, "lint rule"));
303
+ }
304
+ function validateLintRuleSet(value) {
305
+ const candidate = expectRecord(value, "lint rule set");
306
+ expectOnlyKeys(
307
+ candidate,
308
+ "lint rule set",
309
+ ["schemaVersion", "name", "rules"],
310
+ ["schemaVersion", "name", "rules"]
311
+ );
312
+ if (candidate.schemaVersion !== LINT_RULE_SET_SCHEMA_VERSION) {
313
+ throw new TypeError(
314
+ `unsupported lint rule schema ${String(candidate.schemaVersion)}; expected ${LINT_RULE_SET_SCHEMA_VERSION}`
315
+ );
316
+ }
317
+ const name = expectString(candidate.name, "lint rule set.name", MAX_NAME_LENGTH);
318
+ if (!name.trim()) throw new TypeError("lint rule set.name cannot be blank");
319
+ if (!Array.isArray(candidate.rules) || candidate.rules.length > MAX_RULES) {
320
+ throw new TypeError(`lint rule set.rules must contain at most ${MAX_RULES} rules`);
321
+ }
322
+ const ids = /* @__PURE__ */ new Set();
323
+ let regexPatterns = 0;
324
+ let ruleTerms = 0;
325
+ for (const [index, value2] of candidate.rules.entries()) {
326
+ const rule = validatedRule(value2, `rules[${index}]`);
327
+ if (ids.has(rule.id)) throw new TypeError(`lint rule set contains duplicate id ${rule.id}`);
328
+ ids.add(rule.id);
329
+ const primitive = rule.primitive;
330
+ switch (primitive.kind) {
331
+ case "required-result-check":
332
+ ruleTerms += primitive.factories.length;
333
+ ruleTerms += primitive.factories.reduce((sum, factory) => sum + factory.imported.length, 0);
334
+ break;
335
+ case "required-wrapper-call":
336
+ regexPatterns += 1;
337
+ ruleTerms += primitive.activationImports.length;
338
+ if (primitive.wrapper.syntax === "call") {
339
+ ruleTerms += primitive.wrapper.imports.length;
340
+ ruleTerms += primitive.wrapper.imports.reduce(
341
+ (sum, pattern) => sum + pattern.imported.length,
342
+ 0
343
+ );
344
+ }
345
+ ruleTerms += primitive.operators?.length ?? 0;
346
+ break;
347
+ case "banned-import":
348
+ ruleTerms += primitive.sources.length;
349
+ break;
350
+ case "banned-call-argument":
351
+ ruleTerms += primitive.callees.length + primitive.argumentIndexes.length;
352
+ ruleTerms += primitive.objectPaths.reduce((sum, objectPath) => sum + objectPath.length, 0);
353
+ break;
354
+ case "banned-jsx-element":
355
+ ruleTerms += primitive.elements.length;
356
+ break;
357
+ case "banned-classname-pattern":
358
+ regexPatterns += primitive.patterns.length;
359
+ ruleTerms += (primitive.replacements?.length ?? 0) * 2;
360
+ break;
361
+ }
362
+ }
363
+ if (regexPatterns > MAX_TOTAL_REGEX_PATTERNS) {
364
+ throw new TypeError(
365
+ `lint rule set exceeds ${MAX_TOTAL_REGEX_PATTERNS} total regular expressions`
366
+ );
367
+ }
368
+ if (ruleTerms > MAX_TOTAL_RULE_TERMS) {
369
+ throw new TypeError(`lint rule set exceeds ${MAX_TOTAL_RULE_TERMS} total match terms`);
370
+ }
371
+ let serialized;
372
+ try {
373
+ serialized = JSON.stringify(candidate);
374
+ } catch {
375
+ throw new TypeError("lint rule set must be JSON-serializable data");
376
+ }
377
+ if (new TextEncoder().encode(serialized).byteLength > MAX_LINT_RULE_MANIFEST_BYTES) {
378
+ throw new TypeError(`lint rule set exceeds ${MAX_LINT_RULE_MANIFEST_BYTES} UTF-8 bytes`);
379
+ }
380
+ return deepFreeze(candidate);
381
+ }
382
+
383
+ // src/lint/define.ts
384
+ function defineLintRule(rule) {
385
+ return validateLintRule(rule);
386
+ }
387
+ function defineLintRuleSet(options) {
388
+ return validateLintRuleSet({
389
+ schemaVersion: LINT_RULE_SET_SCHEMA_VERSION,
390
+ name: options.name,
391
+ rules: [...options.rules]
392
+ });
393
+ }
394
+
395
+ // src/lint/rules.ts
396
+ var MONEY_NAME_PATTERN = "(?:^|_)(?:price|amount|subtotal|total|tax|fee|discount|cost)(?:$|_)";
397
+ var SDK_CLIENT_FACTORIES = [
398
+ { source: "@cimplify/sdk", imported: ["createCimplifyClient"] },
399
+ { source: "@cimplify/sdk/server", imported: ["getServerClient"] }
400
+ ];
401
+ var SDK_MODULES = [{ value: "@cimplify/sdk", match: "prefix" }];
402
+ var PARSE_PRICE_IMPORTS = [
403
+ { source: "@cimplify/sdk", imported: ["parsePrice"] },
404
+ { source: "@cimplify/sdk/utils", imported: ["parsePrice"] }
405
+ ];
406
+ var TAILWIND_COLOR_SCALE = "(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-(?:50|100|200|300|400|500|600|700|800|900|950)";
407
+ var COLOR_UTILITY = "(?:accent|bg|border|caret|decoration|divide|fill|from|outline|placeholder|ring|shadow|stroke|text|to|via)";
408
+ var checkResultOkRule = defineLintRule({
409
+ id: "sdk/check-result-ok",
410
+ severity: "error",
411
+ message: "Check `result.ok` before reading `result.value`.",
412
+ help: "Cimplify SDK calls return Result values. Handle the error branch before using the value.",
413
+ primitive: {
414
+ kind: "required-result-check",
415
+ factories: SDK_CLIENT_FACTORIES,
416
+ guardProperty: "ok",
417
+ valueProperty: "value"
418
+ }
419
+ });
420
+ var renderPriceComponentRule = defineLintRule({
421
+ id: "sdk/render-price-component",
422
+ severity: "error",
423
+ message: "Render money with the SDK `Price` component.",
424
+ help: "`Price` applies the active business currency and locale consistently.",
425
+ primitive: {
426
+ kind: "required-wrapper-call",
427
+ context: "jsx-child",
428
+ activationImports: SDK_MODULES,
429
+ subjectNamePattern: MONEY_NAME_PATTERN,
430
+ wrapper: {
431
+ syntax: "jsx",
432
+ source: "@cimplify/sdk/react",
433
+ imported: "Price",
434
+ prop: "amount"
435
+ }
436
+ },
437
+ fix: { kind: "wrap-jsx-expression" }
438
+ });
439
+ var parsePriceBeforeMathRule = defineLintRule({
440
+ id: "sdk/parse-price-before-math",
441
+ severity: "error",
442
+ message: "Call `parsePrice` before using a money value in numeric operations.",
443
+ help: "Money arrives over the wire as a decimal string; implicit coercion can produce incorrect comparisons and totals.",
444
+ primitive: {
445
+ kind: "required-wrapper-call",
446
+ context: "numeric-operation",
447
+ activationImports: SDK_MODULES,
448
+ subjectNamePattern: MONEY_NAME_PATTERN,
449
+ wrapper: { syntax: "call", imports: PARSE_PRICE_IMPORTS },
450
+ operators: ["+", "-", "*", "/", "%", "**", "<", "<=", ">", ">="]
451
+ }
452
+ });
453
+ var noReactQueryRule = defineLintRule({
454
+ id: "sdk/no-react-query",
455
+ severity: "error",
456
+ message: "Use Cimplify SDK hooks instead of React Query.",
457
+ help: "Use the SDK hooks and their provider-owned cache so cart, catalogue, and account state stay coherent.",
458
+ primitive: {
459
+ kind: "banned-import",
460
+ sources: [
461
+ { value: "react-query", match: "exact" },
462
+ { value: "@tanstack/react-query", match: "prefix" }
463
+ ]
464
+ }
465
+ });
466
+ var noCookieInCacheKeyRule = defineLintRule({
467
+ id: "sdk/no-cookie-in-cache-key",
468
+ severity: "error",
469
+ message: "Remove the Cookie header from this cacheable request.",
470
+ help: "Cookie-bearing requests bypass the shared cache by design. Keep personalized cart/account reads in a client island.",
471
+ primitive: {
472
+ kind: "banned-call-argument",
473
+ callees: ["fetch", "Request"],
474
+ globalCalleesOnly: true,
475
+ argumentIndexes: [1],
476
+ objectPaths: [["headers", "cookie"]],
477
+ caseInsensitive: true
478
+ },
479
+ fix: { kind: "remove-object-property" }
480
+ });
481
+ var noRawImgRule = defineLintRule({
482
+ id: "ui/no-raw-img",
483
+ severity: "warning",
484
+ message: "Use `next/image` instead of a raw `<img>` element.",
485
+ help: "The storefront image loader supplies responsive sizes, modern formats, and intrinsic dimensions.",
486
+ primitive: { kind: "banned-jsx-element", elements: ["img"] }
487
+ });
488
+ var themeTokensOnlyRule = defineLintRule({
489
+ id: "ui/theme-tokens-only",
490
+ severity: "warning",
491
+ message: "Use storefront theme tokens instead of hard-coded color utilities.",
492
+ help: "Define palette changes in `app/globals.css` and consume semantic utilities such as `bg-background` and `text-foreground`.",
493
+ primitive: {
494
+ kind: "banned-classname-pattern",
495
+ patterns: [
496
+ `^${COLOR_UTILITY}-${TAILWIND_COLOR_SCALE}$`,
497
+ `^${COLOR_UTILITY}-(?:black|white)$`,
498
+ `^${COLOR_UTILITY}-\\[(?:#|rgba?\\(|hsla?\\(|oklch\\(|oklab\\(|lab\\(|lch\\(|color:)`
499
+ ],
500
+ replacements: [
501
+ { from: "bg-white", to: "bg-background" },
502
+ { from: "bg-black", to: "bg-foreground" },
503
+ { from: "text-black", to: "text-foreground" },
504
+ { from: "border-black", to: "border-foreground" },
505
+ { from: "border-white", to: "border-background" }
506
+ ]
507
+ },
508
+ fix: { kind: "replace-classname" }
509
+ });
510
+ var starterLintRuleSet = defineLintRuleSet({
511
+ name: "@cimplify/sdk/starter",
512
+ rules: [
513
+ checkResultOkRule,
514
+ renderPriceComponentRule,
515
+ parsePriceBeforeMathRule,
516
+ noReactQueryRule,
517
+ noCookieInCacheKeyRule,
518
+ noRawImgRule,
519
+ themeTokensOnlyRule
520
+ ]
521
+ });
522
+ var starterLintRules = starterLintRuleSet.rules;
523
+
524
+ export { LINT_RULE_SET_SCHEMA_VERSION, MAX_LINT_RULE_MANIFEST_BYTES, checkResultOkRule, defineLintRule, defineLintRuleSet, noCookieInCacheKeyRule, noRawImgRule, noReactQueryRule, parsePriceBeforeMathRule, renderPriceComponentRule, starterLintRuleSet, starterLintRules, themeTokensOnlyRule, validateLintRule, validateLintRuleSet };
package/dist/mock/cli.mjs CHANGED
@@ -3478,7 +3478,7 @@ function buildV1(deps) {
3478
3478
  });
3479
3479
  app.post("/activity/events", async (c) => {
3480
3480
  const body = await c.req.json().catch(() => ({}));
3481
- return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, c.var.session.id, body.events ?? []));
3481
+ return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, body.analytics_session_id ?? c.var.session.id, body.events ?? []));
3482
3482
  });
3483
3483
  app.get("/activity/state", (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id)));
3484
3484
  app.get("/activity/recommendations", (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId)));
@@ -6441,7 +6441,7 @@ function createActivityService(opts) {
6441
6441
  id,
6442
6442
  business_id: businessId,
6443
6443
  session_id: sessionId,
6444
- event_type: e.event_type,
6444
+ event_type: e.type,
6445
6445
  payload: e.payload ?? {},
6446
6446
  created_at: clock.iso()
6447
6447
  };
@@ -6654,6 +6654,13 @@ function createLiteService(opts) {
6654
6654
  }
6655
6655
 
6656
6656
  // src/mock/domain/link.ts
6657
+ var LOCATION_FIELDS = [
6658
+ "street_address",
6659
+ "city",
6660
+ "region",
6661
+ "postal_code",
6662
+ "country"
6663
+ ];
6657
6664
  var NOT_ENROLLED_ERROR = () => {
6658
6665
  throw {
6659
6666
  code: "NOT_ENROLLED",
@@ -6830,7 +6837,30 @@ function createLinkService({ clock, ids }) {
6830
6837
  },
6831
6838
  updateAddress(customerId, id, patch) {
6832
6839
  const a = this.getAddressById(customerId, id);
6833
- Object.assign(a, patch, { updated_at: clock.iso() });
6840
+ const {
6841
+ clear_coordinates: clearCoordinates = false,
6842
+ latitude,
6843
+ longitude,
6844
+ ...changes
6845
+ } = patch;
6846
+ const hasLatitude = latitude !== void 0;
6847
+ const hasLongitude = longitude !== void 0;
6848
+ if (hasLatitude !== hasLongitude) {
6849
+ throw new Error("latitude and longitude must be supplied together");
6850
+ }
6851
+ if (clearCoordinates && hasLatitude) {
6852
+ throw new Error("clear_coordinates cannot be combined with coordinates");
6853
+ }
6854
+ const locationChanged = LOCATION_FIELDS.some((field) => field in changes);
6855
+ Object.assign(a, changes);
6856
+ if (hasLatitude && hasLongitude) {
6857
+ a.latitude = latitude ?? null;
6858
+ a.longitude = longitude ?? null;
6859
+ } else if (clearCoordinates || locationChanged) {
6860
+ a.latitude = null;
6861
+ a.longitude = null;
6862
+ }
6863
+ a.updated_at = clock.iso();
6834
6864
  return a;
6835
6865
  },
6836
6866
  deleteAddress(customerId, id) {
@@ -2540,7 +2540,7 @@ function buildV1(deps) {
2540
2540
  });
2541
2541
  app.post("/activity/events", async (c) => {
2542
2542
  const body = await c.req.json().catch(() => ({}));
2543
- return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, c.var.session.id, body.events ?? []));
2543
+ return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, body.analytics_session_id ?? c.var.session.id, body.events ?? []));
2544
2544
  });
2545
2545
  app.get("/activity/state", (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id)));
2546
2546
  app.get("/activity/recommendations", (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId)));
@@ -5503,7 +5503,7 @@ function createActivityService(opts) {
5503
5503
  id,
5504
5504
  business_id: businessId,
5505
5505
  session_id: sessionId,
5506
- event_type: e.event_type,
5506
+ event_type: e.type,
5507
5507
  payload: e.payload ?? {},
5508
5508
  created_at: clock.iso()
5509
5509
  };
@@ -5716,6 +5716,13 @@ function createLiteService(opts) {
5716
5716
  }
5717
5717
 
5718
5718
  // src/mock/domain/link.ts
5719
+ var LOCATION_FIELDS = [
5720
+ "street_address",
5721
+ "city",
5722
+ "region",
5723
+ "postal_code",
5724
+ "country"
5725
+ ];
5719
5726
  var NOT_ENROLLED_ERROR = () => {
5720
5727
  throw {
5721
5728
  code: "NOT_ENROLLED",
@@ -5892,7 +5899,30 @@ function createLinkService({ clock, ids }) {
5892
5899
  },
5893
5900
  updateAddress(customerId, id, patch) {
5894
5901
  const a = this.getAddressById(customerId, id);
5895
- Object.assign(a, patch, { updated_at: clock.iso() });
5902
+ const {
5903
+ clear_coordinates: clearCoordinates = false,
5904
+ latitude,
5905
+ longitude,
5906
+ ...changes
5907
+ } = patch;
5908
+ const hasLatitude = latitude !== void 0;
5909
+ const hasLongitude = longitude !== void 0;
5910
+ if (hasLatitude !== hasLongitude) {
5911
+ throw new Error("latitude and longitude must be supplied together");
5912
+ }
5913
+ if (clearCoordinates && hasLatitude) {
5914
+ throw new Error("clear_coordinates cannot be combined with coordinates");
5915
+ }
5916
+ const locationChanged = LOCATION_FIELDS.some((field) => field in changes);
5917
+ Object.assign(a, changes);
5918
+ if (hasLatitude && hasLongitude) {
5919
+ a.latitude = latitude ?? null;
5920
+ a.longitude = longitude ?? null;
5921
+ } else if (clearCoordinates || locationChanged) {
5922
+ a.latitude = null;
5923
+ a.longitude = null;
5924
+ }
5925
+ a.updated_at = clock.iso();
5896
5926
  return a;
5897
5927
  },
5898
5928
  deleteAddress(customerId, id) {