@uniforge/testing 0.1.0-alpha.2

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 (85) hide show
  1. package/dist/auth/index.d.cts +177 -0
  2. package/dist/auth/index.d.ts +177 -0
  3. package/dist/auth/index.js +459 -0
  4. package/dist/auth/index.js.map +1 -0
  5. package/dist/auth/index.mjs +418 -0
  6. package/dist/auth/index.mjs.map +1 -0
  7. package/dist/billing/index.d.cts +27 -0
  8. package/dist/billing/index.d.ts +27 -0
  9. package/dist/billing/index.js +208 -0
  10. package/dist/billing/index.js.map +1 -0
  11. package/dist/billing/index.mjs +178 -0
  12. package/dist/billing/index.mjs.map +1 -0
  13. package/dist/database/index.d.cts +399 -0
  14. package/dist/database/index.d.ts +399 -0
  15. package/dist/database/index.js +19054 -0
  16. package/dist/database/index.js.map +1 -0
  17. package/dist/database/index.mjs +19046 -0
  18. package/dist/database/index.mjs.map +1 -0
  19. package/dist/graphql/index.d.cts +23 -0
  20. package/dist/graphql/index.d.ts +23 -0
  21. package/dist/graphql/index.js +18511 -0
  22. package/dist/graphql/index.js.map +1 -0
  23. package/dist/graphql/index.mjs +18505 -0
  24. package/dist/graphql/index.mjs.map +1 -0
  25. package/dist/index.d.cts +10 -0
  26. package/dist/index.d.ts +10 -0
  27. package/dist/index.js +31 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/index.mjs +6 -0
  30. package/dist/index.mjs.map +1 -0
  31. package/dist/multi-store/index.d.cts +66 -0
  32. package/dist/multi-store/index.d.ts +66 -0
  33. package/dist/multi-store/index.js +319 -0
  34. package/dist/multi-store/index.js.map +1 -0
  35. package/dist/multi-store/index.mjs +287 -0
  36. package/dist/multi-store/index.mjs.map +1 -0
  37. package/dist/multi-tenant/index.d.cts +15 -0
  38. package/dist/multi-tenant/index.d.ts +15 -0
  39. package/dist/multi-tenant/index.js +87 -0
  40. package/dist/multi-tenant/index.js.map +1 -0
  41. package/dist/multi-tenant/index.mjs +57 -0
  42. package/dist/multi-tenant/index.mjs.map +1 -0
  43. package/dist/performance/index.d.cts +60 -0
  44. package/dist/performance/index.d.ts +60 -0
  45. package/dist/performance/index.js +280 -0
  46. package/dist/performance/index.js.map +1 -0
  47. package/dist/performance/index.mjs +246 -0
  48. package/dist/performance/index.mjs.map +1 -0
  49. package/dist/platform/index.d.cts +71 -0
  50. package/dist/platform/index.d.ts +71 -0
  51. package/dist/platform/index.js +435 -0
  52. package/dist/platform/index.js.map +1 -0
  53. package/dist/platform/index.mjs +396 -0
  54. package/dist/platform/index.mjs.map +1 -0
  55. package/dist/rbac/index.d.cts +21 -0
  56. package/dist/rbac/index.d.ts +21 -0
  57. package/dist/rbac/index.js +178 -0
  58. package/dist/rbac/index.js.map +1 -0
  59. package/dist/rbac/index.mjs +150 -0
  60. package/dist/rbac/index.mjs.map +1 -0
  61. package/dist/security/index.d.cts +73 -0
  62. package/dist/security/index.d.ts +73 -0
  63. package/dist/security/index.js +246 -0
  64. package/dist/security/index.js.map +1 -0
  65. package/dist/security/index.mjs +211 -0
  66. package/dist/security/index.mjs.map +1 -0
  67. package/dist/shopify-api/index.d.cts +139 -0
  68. package/dist/shopify-api/index.d.ts +139 -0
  69. package/dist/shopify-api/index.js +469 -0
  70. package/dist/shopify-api/index.js.map +1 -0
  71. package/dist/shopify-api/index.mjs +439 -0
  72. package/dist/shopify-api/index.mjs.map +1 -0
  73. package/dist/shopify-compliance/index.d.cts +85 -0
  74. package/dist/shopify-compliance/index.d.ts +85 -0
  75. package/dist/shopify-compliance/index.js +287 -0
  76. package/dist/shopify-compliance/index.js.map +1 -0
  77. package/dist/shopify-compliance/index.mjs +259 -0
  78. package/dist/shopify-compliance/index.mjs.map +1 -0
  79. package/dist/webhooks/index.d.cts +127 -0
  80. package/dist/webhooks/index.d.ts +127 -0
  81. package/dist/webhooks/index.js +18934 -0
  82. package/dist/webhooks/index.js.map +1 -0
  83. package/dist/webhooks/index.mjs +18916 -0
  84. package/dist/webhooks/index.mjs.map +1 -0
  85. package/package.json +112 -0
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/shopify-compliance/index.ts
21
+ var shopify_compliance_exports = {};
22
+ __export(shopify_compliance_exports, {
23
+ BUILT_FOR_SHOPIFY_CHECKS: () => BUILT_FOR_SHOPIFY_CHECKS,
24
+ ComplianceChecker: () => ComplianceChecker
25
+ });
26
+ module.exports = __toCommonJS(shopify_compliance_exports);
27
+
28
+ // src/shopify-compliance/compliance-checks.ts
29
+ function createCheck(id, name, category, severity, configKey, passMessage, failMessage) {
30
+ return {
31
+ id,
32
+ name,
33
+ category,
34
+ severity,
35
+ check(config) {
36
+ const passed = config[configKey] === true;
37
+ return {
38
+ id,
39
+ name,
40
+ category,
41
+ severity,
42
+ passed,
43
+ message: passed ? passMessage : failMessage
44
+ };
45
+ }
46
+ };
47
+ }
48
+ var BUILT_FOR_SHOPIFY_CHECKS = [
49
+ // Required - authentication
50
+ createCheck(
51
+ "auth-offline-tokens",
52
+ "App uses offline access tokens",
53
+ "authentication",
54
+ "required",
55
+ "hasOfflineTokens",
56
+ "App correctly uses offline access tokens",
57
+ "App must use offline access tokens for background operations"
58
+ ),
59
+ createCheck(
60
+ "auth-session-management",
61
+ "App has session management",
62
+ "authentication",
63
+ "required",
64
+ "hasSessionManagement",
65
+ "App has proper session management",
66
+ "App must implement session management for user authentication"
67
+ ),
68
+ // Required - webhooks
69
+ createCheck(
70
+ "webhook-app-uninstall",
71
+ "Handles APP_UNINSTALLED webhook",
72
+ "webhooks",
73
+ "required",
74
+ "hasAppUninstallHandler",
75
+ "App handles APP_UNINSTALLED webhook correctly",
76
+ "App must handle APP_UNINSTALLED webhook to clean up data"
77
+ ),
78
+ {
79
+ id: "webhook-gdpr",
80
+ name: "Has GDPR compliance endpoints",
81
+ category: "gdpr",
82
+ severity: "required",
83
+ check(config) {
84
+ const passed = config.hasGDPREndpoints === true;
85
+ return {
86
+ id: this.id,
87
+ name: this.name,
88
+ category: this.category,
89
+ severity: this.severity,
90
+ passed,
91
+ message: passed ? "App has GDPR compliance endpoints (customers/data_request, customers/redact, shop/redact)" : "App must implement GDPR endpoints: customers/data_request, customers/redact, shop/redact"
92
+ };
93
+ }
94
+ },
95
+ createCheck(
96
+ "webhook-handlers",
97
+ "Has webhook handlers registered",
98
+ "webhooks",
99
+ "required",
100
+ "hasWebhookHandlers",
101
+ "App has webhook handlers registered",
102
+ "App must register webhook handlers for required events"
103
+ ),
104
+ // Required - security
105
+ createCheck(
106
+ "security-headers",
107
+ "Uses security headers",
108
+ "security",
109
+ "required",
110
+ "hasSecurityHeaders",
111
+ "App uses security headers (HSTS, X-Content-Type-Options, etc.)",
112
+ "App must use security headers (HSTS, X-Content-Type-Options, X-Frame-Options)"
113
+ ),
114
+ createCheck(
115
+ "security-input-validation",
116
+ "Validates user input",
117
+ "security",
118
+ "required",
119
+ "hasInputValidation",
120
+ "App validates user input properly",
121
+ "App must validate and sanitize all user input"
122
+ ),
123
+ createCheck(
124
+ "security-csp",
125
+ "Has Content Security Policy",
126
+ "security",
127
+ "required",
128
+ "hasContentSecurityPolicy",
129
+ "App has Content Security Policy configured",
130
+ "App must implement Content Security Policy headers"
131
+ ),
132
+ // Required - api_usage
133
+ createCheck(
134
+ "api-rate-limiting",
135
+ "Implements rate limiting",
136
+ "api_usage",
137
+ "required",
138
+ "hasRateLimiting",
139
+ "App implements rate limiting and respects Shopify API limits",
140
+ "App must implement rate limiting and respect Shopify API rate limits"
141
+ ),
142
+ createCheck(
143
+ "api-retry-logic",
144
+ "Has retry logic for API calls",
145
+ "api_usage",
146
+ "required",
147
+ "hasRetryLogic",
148
+ "App has retry logic with exponential backoff for API calls",
149
+ "App must implement retry logic with backoff for transient API failures"
150
+ ),
151
+ createCheck(
152
+ "api-error-handling",
153
+ "Has proper error handling",
154
+ "api_usage",
155
+ "required",
156
+ "hasErrorHandling",
157
+ "App has proper error handling for API responses",
158
+ "App must handle API errors gracefully and provide user feedback"
159
+ ),
160
+ // Recommended - billing
161
+ createCheck(
162
+ "billing-integration",
163
+ "Has billing/subscription integration",
164
+ "billing",
165
+ "recommended",
166
+ "hasBillingIntegration",
167
+ "App has billing/subscription integration with Shopify",
168
+ "App should integrate with Shopify billing API for subscriptions"
169
+ ),
170
+ // Recommended - performance
171
+ {
172
+ id: "perf-response-time",
173
+ name: "Average response time under 500ms",
174
+ category: "performance",
175
+ severity: "recommended",
176
+ check(config) {
177
+ const avgTime = config.avgResponseTimeMs;
178
+ const passed = avgTime !== void 0 && avgTime < 500;
179
+ const result = {
180
+ id: this.id,
181
+ name: this.name,
182
+ category: this.category,
183
+ severity: this.severity,
184
+ passed,
185
+ message: passed ? `Average response time (${avgTime}ms) is under 500ms` : "Average response time should be under 500ms"
186
+ };
187
+ if (avgTime !== void 0) {
188
+ result.details = `Current average: ${avgTime}ms`;
189
+ }
190
+ return result;
191
+ }
192
+ },
193
+ createCheck(
194
+ "perf-optimization",
195
+ "Has performance optimization",
196
+ "performance",
197
+ "recommended",
198
+ "hasPerformanceOptimization",
199
+ "App has performance optimizations (caching, lazy loading, etc.)",
200
+ "App should implement performance optimizations such as caching"
201
+ ),
202
+ // Optional - ux
203
+ createCheck(
204
+ "ux-i18n",
205
+ "Supports multiple languages",
206
+ "ux",
207
+ "optional",
208
+ "supportsMultipleLanguages",
209
+ "App supports multiple languages for international merchants",
210
+ "Consider adding multi-language support for broader reach"
211
+ ),
212
+ createCheck(
213
+ "ux-accessibility",
214
+ "Has accessibility compliance",
215
+ "ux",
216
+ "optional",
217
+ "hasAccessibilityCompliance",
218
+ "App meets accessibility standards (WCAG)",
219
+ "Consider implementing accessibility features (WCAG compliance)"
220
+ )
221
+ ];
222
+
223
+ // src/shopify-compliance/compliance-checker.ts
224
+ var ComplianceChecker = class {
225
+ checks;
226
+ constructor(checks) {
227
+ this.checks = checks ?? BUILT_FOR_SHOPIFY_CHECKS;
228
+ }
229
+ runAll(config) {
230
+ const results = this.checks.map((c) => c.check(config));
231
+ const score = this.generateScore(results);
232
+ const summary = this.buildSummary(results);
233
+ return {
234
+ appName: config.appName,
235
+ checkedAt: /* @__PURE__ */ new Date(),
236
+ totalChecks: results.length,
237
+ passed: results.filter((r) => r.passed).length,
238
+ failed: results.filter((r) => !r.passed && r.severity === "required").length,
239
+ warnings: results.filter((r) => !r.passed && r.severity !== "required").length,
240
+ score,
241
+ checks: results,
242
+ summary
243
+ };
244
+ }
245
+ runCategory(config, category) {
246
+ return this.checks.filter((c) => c.category === category).map((c) => c.check(config));
247
+ }
248
+ getEligibility(config) {
249
+ const results = this.checks.map((c) => c.check(config));
250
+ const blockers = results.filter((r) => r.severity === "required" && !r.passed);
251
+ return {
252
+ eligible: blockers.length === 0,
253
+ blockers
254
+ };
255
+ }
256
+ generateScore(results) {
257
+ const required = results.filter((r) => r.severity === "required");
258
+ const recommended = results.filter((r) => r.severity === "recommended");
259
+ const optional = results.filter((r) => r.severity === "optional");
260
+ const requiredScore = required.length > 0 ? required.filter((r) => r.passed).length / required.length * 60 : 60;
261
+ const recommendedScore = recommended.length > 0 ? recommended.filter((r) => r.passed).length / recommended.length * 30 : 30;
262
+ const optionalScore = optional.length > 0 ? optional.filter((r) => r.passed).length / optional.length * 10 : 10;
263
+ return Math.round(requiredScore + recommendedScore + optionalScore);
264
+ }
265
+ buildSummary(results) {
266
+ const required = results.filter((r) => r.severity === "required");
267
+ const recommended = results.filter((r) => r.severity === "recommended");
268
+ const optional = results.filter((r) => r.severity === "optional");
269
+ const requiredPassed = required.filter((r) => r.passed).length;
270
+ const requiredTotal = required.length;
271
+ return {
272
+ requiredPassed,
273
+ requiredTotal,
274
+ recommendedPassed: recommended.filter((r) => r.passed).length,
275
+ recommendedTotal: recommended.length,
276
+ optionalPassed: optional.filter((r) => r.passed).length,
277
+ optionalTotal: optional.length,
278
+ isEligible: requiredPassed === requiredTotal
279
+ };
280
+ }
281
+ };
282
+ // Annotate the CommonJS export names for ESM import in node:
283
+ 0 && (module.exports = {
284
+ BUILT_FOR_SHOPIFY_CHECKS,
285
+ ComplianceChecker
286
+ });
287
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shopify-compliance/index.ts","../../src/shopify-compliance/compliance-checks.ts","../../src/shopify-compliance/compliance-checker.ts"],"sourcesContent":["/**\n * @uniforge/testing - Shopify Compliance\n *\n * Built for Shopify compliance checker and verification utilities.\n */\n\nexport type {\n ComplianceCategory,\n ComplianceCheckConfig,\n ComplianceCheckResult,\n ComplianceReport,\n ComplianceSeverity,\n ComplianceSummary,\n} from './types';\n\nexport type { ComplianceCheck } from './compliance-checks';\nexport { BUILT_FOR_SHOPIFY_CHECKS } from './compliance-checks';\n\nexport { ComplianceChecker } from './compliance-checker';\n","/**\n * Built for Shopify compliance checks.\n */\n\nimport type {\n ComplianceCategory,\n ComplianceCheckConfig,\n ComplianceCheckResult,\n ComplianceSeverity,\n} from './types';\n\nexport interface ComplianceCheck {\n id: string;\n name: string;\n category: ComplianceCategory;\n severity: ComplianceSeverity;\n check: (config: ComplianceCheckConfig) => ComplianceCheckResult;\n}\n\nfunction createCheck(\n id: string,\n name: string,\n category: ComplianceCategory,\n severity: ComplianceSeverity,\n configKey: keyof ComplianceCheckConfig,\n passMessage: string,\n failMessage: string,\n): ComplianceCheck {\n return {\n id,\n name,\n category,\n severity,\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const passed = config[configKey] === true;\n return {\n id,\n name,\n category,\n severity,\n passed,\n message: passed ? passMessage : failMessage,\n };\n },\n };\n}\n\nexport const BUILT_FOR_SHOPIFY_CHECKS: ComplianceCheck[] = [\n // Required - authentication\n createCheck(\n 'auth-offline-tokens',\n 'App uses offline access tokens',\n 'authentication',\n 'required',\n 'hasOfflineTokens',\n 'App correctly uses offline access tokens',\n 'App must use offline access tokens for background operations',\n ),\n createCheck(\n 'auth-session-management',\n 'App has session management',\n 'authentication',\n 'required',\n 'hasSessionManagement',\n 'App has proper session management',\n 'App must implement session management for user authentication',\n ),\n\n // Required - webhooks\n createCheck(\n 'webhook-app-uninstall',\n 'Handles APP_UNINSTALLED webhook',\n 'webhooks',\n 'required',\n 'hasAppUninstallHandler',\n 'App handles APP_UNINSTALLED webhook correctly',\n 'App must handle APP_UNINSTALLED webhook to clean up data',\n ),\n {\n id: 'webhook-gdpr',\n name: 'Has GDPR compliance endpoints',\n category: 'gdpr',\n severity: 'required',\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const passed = config.hasGDPREndpoints === true;\n return {\n id: this.id,\n name: this.name,\n category: this.category,\n severity: this.severity,\n passed,\n message: passed\n ? 'App has GDPR compliance endpoints (customers/data_request, customers/redact, shop/redact)'\n : 'App must implement GDPR endpoints: customers/data_request, customers/redact, shop/redact',\n };\n },\n },\n createCheck(\n 'webhook-handlers',\n 'Has webhook handlers registered',\n 'webhooks',\n 'required',\n 'hasWebhookHandlers',\n 'App has webhook handlers registered',\n 'App must register webhook handlers for required events',\n ),\n\n // Required - security\n createCheck(\n 'security-headers',\n 'Uses security headers',\n 'security',\n 'required',\n 'hasSecurityHeaders',\n 'App uses security headers (HSTS, X-Content-Type-Options, etc.)',\n 'App must use security headers (HSTS, X-Content-Type-Options, X-Frame-Options)',\n ),\n createCheck(\n 'security-input-validation',\n 'Validates user input',\n 'security',\n 'required',\n 'hasInputValidation',\n 'App validates user input properly',\n 'App must validate and sanitize all user input',\n ),\n createCheck(\n 'security-csp',\n 'Has Content Security Policy',\n 'security',\n 'required',\n 'hasContentSecurityPolicy',\n 'App has Content Security Policy configured',\n 'App must implement Content Security Policy headers',\n ),\n\n // Required - api_usage\n createCheck(\n 'api-rate-limiting',\n 'Implements rate limiting',\n 'api_usage',\n 'required',\n 'hasRateLimiting',\n 'App implements rate limiting and respects Shopify API limits',\n 'App must implement rate limiting and respect Shopify API rate limits',\n ),\n createCheck(\n 'api-retry-logic',\n 'Has retry logic for API calls',\n 'api_usage',\n 'required',\n 'hasRetryLogic',\n 'App has retry logic with exponential backoff for API calls',\n 'App must implement retry logic with backoff for transient API failures',\n ),\n createCheck(\n 'api-error-handling',\n 'Has proper error handling',\n 'api_usage',\n 'required',\n 'hasErrorHandling',\n 'App has proper error handling for API responses',\n 'App must handle API errors gracefully and provide user feedback',\n ),\n\n // Recommended - billing\n createCheck(\n 'billing-integration',\n 'Has billing/subscription integration',\n 'billing',\n 'recommended',\n 'hasBillingIntegration',\n 'App has billing/subscription integration with Shopify',\n 'App should integrate with Shopify billing API for subscriptions',\n ),\n\n // Recommended - performance\n {\n id: 'perf-response-time',\n name: 'Average response time under 500ms',\n category: 'performance',\n severity: 'recommended',\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const avgTime = config.avgResponseTimeMs;\n const passed = avgTime !== undefined && avgTime < 500;\n const result: ComplianceCheckResult = {\n id: this.id,\n name: this.name,\n category: this.category,\n severity: this.severity,\n passed,\n message: passed\n ? `Average response time (${avgTime}ms) is under 500ms`\n : 'Average response time should be under 500ms',\n };\n if (avgTime !== undefined) {\n result.details = `Current average: ${avgTime}ms`;\n }\n return result;\n },\n },\n createCheck(\n 'perf-optimization',\n 'Has performance optimization',\n 'performance',\n 'recommended',\n 'hasPerformanceOptimization',\n 'App has performance optimizations (caching, lazy loading, etc.)',\n 'App should implement performance optimizations such as caching',\n ),\n\n // Optional - ux\n createCheck(\n 'ux-i18n',\n 'Supports multiple languages',\n 'ux',\n 'optional',\n 'supportsMultipleLanguages',\n 'App supports multiple languages for international merchants',\n 'Consider adding multi-language support for broader reach',\n ),\n createCheck(\n 'ux-accessibility',\n 'Has accessibility compliance',\n 'ux',\n 'optional',\n 'hasAccessibilityCompliance',\n 'App meets accessibility standards (WCAG)',\n 'Consider implementing accessibility features (WCAG compliance)',\n ),\n];\n","/**\n * Compliance checker for Built for Shopify requirements.\n */\n\nimport type { ComplianceCheck } from './compliance-checks';\nimport { BUILT_FOR_SHOPIFY_CHECKS } from './compliance-checks';\nimport type {\n ComplianceCategory,\n ComplianceCheckConfig,\n ComplianceCheckResult,\n ComplianceReport,\n ComplianceSummary,\n} from './types';\n\nexport class ComplianceChecker {\n private readonly checks: ComplianceCheck[];\n\n constructor(checks?: ComplianceCheck[]) {\n this.checks = checks ?? BUILT_FOR_SHOPIFY_CHECKS;\n }\n\n runAll(config: ComplianceCheckConfig): ComplianceReport {\n const results = this.checks.map((c) => c.check(config));\n const score = this.generateScore(results);\n const summary = this.buildSummary(results);\n\n return {\n appName: config.appName,\n checkedAt: new Date(),\n totalChecks: results.length,\n passed: results.filter((r) => r.passed).length,\n failed: results.filter((r) => !r.passed && r.severity === 'required').length,\n warnings: results.filter((r) => !r.passed && r.severity !== 'required').length,\n score,\n checks: results,\n summary,\n };\n }\n\n runCategory(\n config: ComplianceCheckConfig,\n category: ComplianceCategory,\n ): ComplianceCheckResult[] {\n return this.checks\n .filter((c) => c.category === category)\n .map((c) => c.check(config));\n }\n\n getEligibility(config: ComplianceCheckConfig): {\n eligible: boolean;\n blockers: ComplianceCheckResult[];\n } {\n const results = this.checks.map((c) => c.check(config));\n const blockers = results.filter((r) => r.severity === 'required' && !r.passed);\n return {\n eligible: blockers.length === 0,\n blockers,\n };\n }\n\n generateScore(results: ComplianceCheckResult[]): number {\n const required = results.filter((r) => r.severity === 'required');\n const recommended = results.filter((r) => r.severity === 'recommended');\n const optional = results.filter((r) => r.severity === 'optional');\n\n const requiredScore =\n required.length > 0\n ? (required.filter((r) => r.passed).length / required.length) * 60\n : 60;\n const recommendedScore =\n recommended.length > 0\n ? (recommended.filter((r) => r.passed).length / recommended.length) * 30\n : 30;\n const optionalScore =\n optional.length > 0\n ? (optional.filter((r) => r.passed).length / optional.length) * 10\n : 10;\n\n return Math.round(requiredScore + recommendedScore + optionalScore);\n }\n\n private buildSummary(results: ComplianceCheckResult[]): ComplianceSummary {\n const required = results.filter((r) => r.severity === 'required');\n const recommended = results.filter((r) => r.severity === 'recommended');\n const optional = results.filter((r) => r.severity === 'optional');\n\n const requiredPassed = required.filter((r) => r.passed).length;\n const requiredTotal = required.length;\n\n return {\n requiredPassed,\n requiredTotal,\n recommendedPassed: recommended.filter((r) => r.passed).length,\n recommendedTotal: recommended.length,\n optionalPassed: optional.filter((r) => r.passed).length,\n optionalTotal: optional.length,\n isEligible: requiredPassed === requiredTotal,\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,259 @@
1
+ // src/shopify-compliance/compliance-checks.ts
2
+ function createCheck(id, name, category, severity, configKey, passMessage, failMessage) {
3
+ return {
4
+ id,
5
+ name,
6
+ category,
7
+ severity,
8
+ check(config) {
9
+ const passed = config[configKey] === true;
10
+ return {
11
+ id,
12
+ name,
13
+ category,
14
+ severity,
15
+ passed,
16
+ message: passed ? passMessage : failMessage
17
+ };
18
+ }
19
+ };
20
+ }
21
+ var BUILT_FOR_SHOPIFY_CHECKS = [
22
+ // Required - authentication
23
+ createCheck(
24
+ "auth-offline-tokens",
25
+ "App uses offline access tokens",
26
+ "authentication",
27
+ "required",
28
+ "hasOfflineTokens",
29
+ "App correctly uses offline access tokens",
30
+ "App must use offline access tokens for background operations"
31
+ ),
32
+ createCheck(
33
+ "auth-session-management",
34
+ "App has session management",
35
+ "authentication",
36
+ "required",
37
+ "hasSessionManagement",
38
+ "App has proper session management",
39
+ "App must implement session management for user authentication"
40
+ ),
41
+ // Required - webhooks
42
+ createCheck(
43
+ "webhook-app-uninstall",
44
+ "Handles APP_UNINSTALLED webhook",
45
+ "webhooks",
46
+ "required",
47
+ "hasAppUninstallHandler",
48
+ "App handles APP_UNINSTALLED webhook correctly",
49
+ "App must handle APP_UNINSTALLED webhook to clean up data"
50
+ ),
51
+ {
52
+ id: "webhook-gdpr",
53
+ name: "Has GDPR compliance endpoints",
54
+ category: "gdpr",
55
+ severity: "required",
56
+ check(config) {
57
+ const passed = config.hasGDPREndpoints === true;
58
+ return {
59
+ id: this.id,
60
+ name: this.name,
61
+ category: this.category,
62
+ severity: this.severity,
63
+ passed,
64
+ message: passed ? "App has GDPR compliance endpoints (customers/data_request, customers/redact, shop/redact)" : "App must implement GDPR endpoints: customers/data_request, customers/redact, shop/redact"
65
+ };
66
+ }
67
+ },
68
+ createCheck(
69
+ "webhook-handlers",
70
+ "Has webhook handlers registered",
71
+ "webhooks",
72
+ "required",
73
+ "hasWebhookHandlers",
74
+ "App has webhook handlers registered",
75
+ "App must register webhook handlers for required events"
76
+ ),
77
+ // Required - security
78
+ createCheck(
79
+ "security-headers",
80
+ "Uses security headers",
81
+ "security",
82
+ "required",
83
+ "hasSecurityHeaders",
84
+ "App uses security headers (HSTS, X-Content-Type-Options, etc.)",
85
+ "App must use security headers (HSTS, X-Content-Type-Options, X-Frame-Options)"
86
+ ),
87
+ createCheck(
88
+ "security-input-validation",
89
+ "Validates user input",
90
+ "security",
91
+ "required",
92
+ "hasInputValidation",
93
+ "App validates user input properly",
94
+ "App must validate and sanitize all user input"
95
+ ),
96
+ createCheck(
97
+ "security-csp",
98
+ "Has Content Security Policy",
99
+ "security",
100
+ "required",
101
+ "hasContentSecurityPolicy",
102
+ "App has Content Security Policy configured",
103
+ "App must implement Content Security Policy headers"
104
+ ),
105
+ // Required - api_usage
106
+ createCheck(
107
+ "api-rate-limiting",
108
+ "Implements rate limiting",
109
+ "api_usage",
110
+ "required",
111
+ "hasRateLimiting",
112
+ "App implements rate limiting and respects Shopify API limits",
113
+ "App must implement rate limiting and respect Shopify API rate limits"
114
+ ),
115
+ createCheck(
116
+ "api-retry-logic",
117
+ "Has retry logic for API calls",
118
+ "api_usage",
119
+ "required",
120
+ "hasRetryLogic",
121
+ "App has retry logic with exponential backoff for API calls",
122
+ "App must implement retry logic with backoff for transient API failures"
123
+ ),
124
+ createCheck(
125
+ "api-error-handling",
126
+ "Has proper error handling",
127
+ "api_usage",
128
+ "required",
129
+ "hasErrorHandling",
130
+ "App has proper error handling for API responses",
131
+ "App must handle API errors gracefully and provide user feedback"
132
+ ),
133
+ // Recommended - billing
134
+ createCheck(
135
+ "billing-integration",
136
+ "Has billing/subscription integration",
137
+ "billing",
138
+ "recommended",
139
+ "hasBillingIntegration",
140
+ "App has billing/subscription integration with Shopify",
141
+ "App should integrate with Shopify billing API for subscriptions"
142
+ ),
143
+ // Recommended - performance
144
+ {
145
+ id: "perf-response-time",
146
+ name: "Average response time under 500ms",
147
+ category: "performance",
148
+ severity: "recommended",
149
+ check(config) {
150
+ const avgTime = config.avgResponseTimeMs;
151
+ const passed = avgTime !== void 0 && avgTime < 500;
152
+ const result = {
153
+ id: this.id,
154
+ name: this.name,
155
+ category: this.category,
156
+ severity: this.severity,
157
+ passed,
158
+ message: passed ? `Average response time (${avgTime}ms) is under 500ms` : "Average response time should be under 500ms"
159
+ };
160
+ if (avgTime !== void 0) {
161
+ result.details = `Current average: ${avgTime}ms`;
162
+ }
163
+ return result;
164
+ }
165
+ },
166
+ createCheck(
167
+ "perf-optimization",
168
+ "Has performance optimization",
169
+ "performance",
170
+ "recommended",
171
+ "hasPerformanceOptimization",
172
+ "App has performance optimizations (caching, lazy loading, etc.)",
173
+ "App should implement performance optimizations such as caching"
174
+ ),
175
+ // Optional - ux
176
+ createCheck(
177
+ "ux-i18n",
178
+ "Supports multiple languages",
179
+ "ux",
180
+ "optional",
181
+ "supportsMultipleLanguages",
182
+ "App supports multiple languages for international merchants",
183
+ "Consider adding multi-language support for broader reach"
184
+ ),
185
+ createCheck(
186
+ "ux-accessibility",
187
+ "Has accessibility compliance",
188
+ "ux",
189
+ "optional",
190
+ "hasAccessibilityCompliance",
191
+ "App meets accessibility standards (WCAG)",
192
+ "Consider implementing accessibility features (WCAG compliance)"
193
+ )
194
+ ];
195
+
196
+ // src/shopify-compliance/compliance-checker.ts
197
+ var ComplianceChecker = class {
198
+ checks;
199
+ constructor(checks) {
200
+ this.checks = checks ?? BUILT_FOR_SHOPIFY_CHECKS;
201
+ }
202
+ runAll(config) {
203
+ const results = this.checks.map((c) => c.check(config));
204
+ const score = this.generateScore(results);
205
+ const summary = this.buildSummary(results);
206
+ return {
207
+ appName: config.appName,
208
+ checkedAt: /* @__PURE__ */ new Date(),
209
+ totalChecks: results.length,
210
+ passed: results.filter((r) => r.passed).length,
211
+ failed: results.filter((r) => !r.passed && r.severity === "required").length,
212
+ warnings: results.filter((r) => !r.passed && r.severity !== "required").length,
213
+ score,
214
+ checks: results,
215
+ summary
216
+ };
217
+ }
218
+ runCategory(config, category) {
219
+ return this.checks.filter((c) => c.category === category).map((c) => c.check(config));
220
+ }
221
+ getEligibility(config) {
222
+ const results = this.checks.map((c) => c.check(config));
223
+ const blockers = results.filter((r) => r.severity === "required" && !r.passed);
224
+ return {
225
+ eligible: blockers.length === 0,
226
+ blockers
227
+ };
228
+ }
229
+ generateScore(results) {
230
+ const required = results.filter((r) => r.severity === "required");
231
+ const recommended = results.filter((r) => r.severity === "recommended");
232
+ const optional = results.filter((r) => r.severity === "optional");
233
+ const requiredScore = required.length > 0 ? required.filter((r) => r.passed).length / required.length * 60 : 60;
234
+ const recommendedScore = recommended.length > 0 ? recommended.filter((r) => r.passed).length / recommended.length * 30 : 30;
235
+ const optionalScore = optional.length > 0 ? optional.filter((r) => r.passed).length / optional.length * 10 : 10;
236
+ return Math.round(requiredScore + recommendedScore + optionalScore);
237
+ }
238
+ buildSummary(results) {
239
+ const required = results.filter((r) => r.severity === "required");
240
+ const recommended = results.filter((r) => r.severity === "recommended");
241
+ const optional = results.filter((r) => r.severity === "optional");
242
+ const requiredPassed = required.filter((r) => r.passed).length;
243
+ const requiredTotal = required.length;
244
+ return {
245
+ requiredPassed,
246
+ requiredTotal,
247
+ recommendedPassed: recommended.filter((r) => r.passed).length,
248
+ recommendedTotal: recommended.length,
249
+ optionalPassed: optional.filter((r) => r.passed).length,
250
+ optionalTotal: optional.length,
251
+ isEligible: requiredPassed === requiredTotal
252
+ };
253
+ }
254
+ };
255
+ export {
256
+ BUILT_FOR_SHOPIFY_CHECKS,
257
+ ComplianceChecker
258
+ };
259
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/shopify-compliance/compliance-checks.ts","../../src/shopify-compliance/compliance-checker.ts"],"sourcesContent":["/**\n * Built for Shopify compliance checks.\n */\n\nimport type {\n ComplianceCategory,\n ComplianceCheckConfig,\n ComplianceCheckResult,\n ComplianceSeverity,\n} from './types';\n\nexport interface ComplianceCheck {\n id: string;\n name: string;\n category: ComplianceCategory;\n severity: ComplianceSeverity;\n check: (config: ComplianceCheckConfig) => ComplianceCheckResult;\n}\n\nfunction createCheck(\n id: string,\n name: string,\n category: ComplianceCategory,\n severity: ComplianceSeverity,\n configKey: keyof ComplianceCheckConfig,\n passMessage: string,\n failMessage: string,\n): ComplianceCheck {\n return {\n id,\n name,\n category,\n severity,\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const passed = config[configKey] === true;\n return {\n id,\n name,\n category,\n severity,\n passed,\n message: passed ? passMessage : failMessage,\n };\n },\n };\n}\n\nexport const BUILT_FOR_SHOPIFY_CHECKS: ComplianceCheck[] = [\n // Required - authentication\n createCheck(\n 'auth-offline-tokens',\n 'App uses offline access tokens',\n 'authentication',\n 'required',\n 'hasOfflineTokens',\n 'App correctly uses offline access tokens',\n 'App must use offline access tokens for background operations',\n ),\n createCheck(\n 'auth-session-management',\n 'App has session management',\n 'authentication',\n 'required',\n 'hasSessionManagement',\n 'App has proper session management',\n 'App must implement session management for user authentication',\n ),\n\n // Required - webhooks\n createCheck(\n 'webhook-app-uninstall',\n 'Handles APP_UNINSTALLED webhook',\n 'webhooks',\n 'required',\n 'hasAppUninstallHandler',\n 'App handles APP_UNINSTALLED webhook correctly',\n 'App must handle APP_UNINSTALLED webhook to clean up data',\n ),\n {\n id: 'webhook-gdpr',\n name: 'Has GDPR compliance endpoints',\n category: 'gdpr',\n severity: 'required',\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const passed = config.hasGDPREndpoints === true;\n return {\n id: this.id,\n name: this.name,\n category: this.category,\n severity: this.severity,\n passed,\n message: passed\n ? 'App has GDPR compliance endpoints (customers/data_request, customers/redact, shop/redact)'\n : 'App must implement GDPR endpoints: customers/data_request, customers/redact, shop/redact',\n };\n },\n },\n createCheck(\n 'webhook-handlers',\n 'Has webhook handlers registered',\n 'webhooks',\n 'required',\n 'hasWebhookHandlers',\n 'App has webhook handlers registered',\n 'App must register webhook handlers for required events',\n ),\n\n // Required - security\n createCheck(\n 'security-headers',\n 'Uses security headers',\n 'security',\n 'required',\n 'hasSecurityHeaders',\n 'App uses security headers (HSTS, X-Content-Type-Options, etc.)',\n 'App must use security headers (HSTS, X-Content-Type-Options, X-Frame-Options)',\n ),\n createCheck(\n 'security-input-validation',\n 'Validates user input',\n 'security',\n 'required',\n 'hasInputValidation',\n 'App validates user input properly',\n 'App must validate and sanitize all user input',\n ),\n createCheck(\n 'security-csp',\n 'Has Content Security Policy',\n 'security',\n 'required',\n 'hasContentSecurityPolicy',\n 'App has Content Security Policy configured',\n 'App must implement Content Security Policy headers',\n ),\n\n // Required - api_usage\n createCheck(\n 'api-rate-limiting',\n 'Implements rate limiting',\n 'api_usage',\n 'required',\n 'hasRateLimiting',\n 'App implements rate limiting and respects Shopify API limits',\n 'App must implement rate limiting and respect Shopify API rate limits',\n ),\n createCheck(\n 'api-retry-logic',\n 'Has retry logic for API calls',\n 'api_usage',\n 'required',\n 'hasRetryLogic',\n 'App has retry logic with exponential backoff for API calls',\n 'App must implement retry logic with backoff for transient API failures',\n ),\n createCheck(\n 'api-error-handling',\n 'Has proper error handling',\n 'api_usage',\n 'required',\n 'hasErrorHandling',\n 'App has proper error handling for API responses',\n 'App must handle API errors gracefully and provide user feedback',\n ),\n\n // Recommended - billing\n createCheck(\n 'billing-integration',\n 'Has billing/subscription integration',\n 'billing',\n 'recommended',\n 'hasBillingIntegration',\n 'App has billing/subscription integration with Shopify',\n 'App should integrate with Shopify billing API for subscriptions',\n ),\n\n // Recommended - performance\n {\n id: 'perf-response-time',\n name: 'Average response time under 500ms',\n category: 'performance',\n severity: 'recommended',\n check(config: ComplianceCheckConfig): ComplianceCheckResult {\n const avgTime = config.avgResponseTimeMs;\n const passed = avgTime !== undefined && avgTime < 500;\n const result: ComplianceCheckResult = {\n id: this.id,\n name: this.name,\n category: this.category,\n severity: this.severity,\n passed,\n message: passed\n ? `Average response time (${avgTime}ms) is under 500ms`\n : 'Average response time should be under 500ms',\n };\n if (avgTime !== undefined) {\n result.details = `Current average: ${avgTime}ms`;\n }\n return result;\n },\n },\n createCheck(\n 'perf-optimization',\n 'Has performance optimization',\n 'performance',\n 'recommended',\n 'hasPerformanceOptimization',\n 'App has performance optimizations (caching, lazy loading, etc.)',\n 'App should implement performance optimizations such as caching',\n ),\n\n // Optional - ux\n createCheck(\n 'ux-i18n',\n 'Supports multiple languages',\n 'ux',\n 'optional',\n 'supportsMultipleLanguages',\n 'App supports multiple languages for international merchants',\n 'Consider adding multi-language support for broader reach',\n ),\n createCheck(\n 'ux-accessibility',\n 'Has accessibility compliance',\n 'ux',\n 'optional',\n 'hasAccessibilityCompliance',\n 'App meets accessibility standards (WCAG)',\n 'Consider implementing accessibility features (WCAG compliance)',\n ),\n];\n","/**\n * Compliance checker for Built for Shopify requirements.\n */\n\nimport type { ComplianceCheck } from './compliance-checks';\nimport { BUILT_FOR_SHOPIFY_CHECKS } from './compliance-checks';\nimport type {\n ComplianceCategory,\n ComplianceCheckConfig,\n ComplianceCheckResult,\n ComplianceReport,\n ComplianceSummary,\n} from './types';\n\nexport class ComplianceChecker {\n private readonly checks: ComplianceCheck[];\n\n constructor(checks?: ComplianceCheck[]) {\n this.checks = checks ?? BUILT_FOR_SHOPIFY_CHECKS;\n }\n\n runAll(config: ComplianceCheckConfig): ComplianceReport {\n const results = this.checks.map((c) => c.check(config));\n const score = this.generateScore(results);\n const summary = this.buildSummary(results);\n\n return {\n appName: config.appName,\n checkedAt: new Date(),\n totalChecks: results.length,\n passed: results.filter((r) => r.passed).length,\n failed: results.filter((r) => !r.passed && r.severity === 'required').length,\n warnings: results.filter((r) => !r.passed && r.severity !== 'required').length,\n score,\n checks: results,\n summary,\n };\n }\n\n runCategory(\n config: ComplianceCheckConfig,\n category: ComplianceCategory,\n ): ComplianceCheckResult[] {\n return this.checks\n .filter((c) => c.category === category)\n .map((c) => c.check(config));\n }\n\n getEligibility(config: ComplianceCheckConfig): {\n eligible: boolean;\n blockers: ComplianceCheckResult[];\n } {\n const results = this.checks.map((c) => c.check(config));\n const blockers = results.filter((r) => r.severity === 'required' && !r.passed);\n return {\n eligible: blockers.length === 0,\n blockers,\n };\n }\n\n generateScore(results: ComplianceCheckResult[]): number {\n const required = results.filter((r) => r.severity === 'required');\n const recommended = results.filter((r) => r.severity === 'recommended');\n const optional = results.filter((r) => r.severity === 'optional');\n\n const requiredScore =\n required.length > 0\n ? (required.filter((r) => r.passed).length / required.length) * 60\n : 60;\n const recommendedScore =\n recommended.length > 0\n ? (recommended.filter((r) => r.passed).length / recommended.length) * 30\n : 30;\n const optionalScore =\n optional.length > 0\n ? (optional.filter((r) => r.passed).length / optional.length) * 10\n : 10;\n\n return Math.round(requiredScore + recommendedScore + optionalScore);\n }\n\n private buildSummary(results: ComplianceCheckResult[]): ComplianceSummary {\n const required = results.filter((r) => r.severity === 'required');\n const recommended = results.filter((r) => r.severity === 'recommended');\n const optional = results.filter((r) => r.severity === 'optional');\n\n const requiredPassed = required.filter((r) => r.passed).length;\n const requiredTotal = required.length;\n\n return {\n requiredPassed,\n requiredTotal,\n recommendedPassed: recommended.filter((r) => r.passed).length,\n recommendedTotal: recommended.length,\n optionalPassed: optional.filter((r) => r.passed).length,\n optionalTotal: optional.length,\n isEligible: requiredPassed === requiredTotal,\n };\n }\n}\n"],"mappings":"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","names":[]}