@swell/cli 2.2.0 → 2.3.0

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 (79) hide show
  1. package/dist/app-command.js +1 -1
  2. package/dist/commands/api/delete.js +4 -1
  3. package/dist/commands/api/get.js +1 -0
  4. package/dist/commands/api/index.js +4 -1
  5. package/dist/commands/api/post.js +1 -0
  6. package/dist/commands/api/put.js +1 -0
  7. package/dist/commands/app/dev.js +5 -3
  8. package/dist/commands/app/init.d.ts +8 -7
  9. package/dist/commands/app/init.js +36 -18
  10. package/dist/commands/app/pull.js +2 -2
  11. package/dist/commands/app/push.js +2 -2
  12. package/dist/commands/app/version.d.ts +1 -0
  13. package/dist/commands/app/version.js +14 -4
  14. package/dist/commands/create/app.d.ts +8 -4
  15. package/dist/commands/create/app.js +68 -51
  16. package/dist/commands/create/content.d.ts +5 -6
  17. package/dist/commands/create/content.js +22 -38
  18. package/dist/commands/create/function.d.ts +6 -7
  19. package/dist/commands/create/function.js +94 -31
  20. package/dist/commands/create/index.js +13 -1
  21. package/dist/commands/create/model.d.ts +5 -6
  22. package/dist/commands/create/model.js +21 -33
  23. package/dist/commands/create/notification.d.ts +9 -9
  24. package/dist/commands/create/notification.js +117 -95
  25. package/dist/commands/create/setting.d.ts +21 -0
  26. package/dist/commands/create/setting.js +120 -0
  27. package/dist/commands/create/tests.d.ts +14 -0
  28. package/dist/commands/create/tests.js +76 -0
  29. package/dist/commands/create/webhook.d.ts +22 -0
  30. package/dist/commands/create/webhook.js +176 -0
  31. package/dist/commands/inspect/content.js +1 -1
  32. package/dist/commands/schema.d.ts +1 -0
  33. package/dist/commands/schema.js +51 -5
  34. package/dist/commands/theme/init.d.ts +8 -4
  35. package/dist/commands/theme/init.js +21 -8
  36. package/dist/create-app-command.d.ts +1 -0
  37. package/dist/create-app-command.js +15 -10
  38. package/dist/create-config-command.js +2 -2
  39. package/dist/help/custom-help.d.ts +89 -0
  40. package/dist/help/custom-help.js +337 -0
  41. package/dist/help/types.d.ts +75 -0
  42. package/dist/help/types.js +1 -0
  43. package/dist/lib/apps/app-config.js +2 -2
  44. package/dist/lib/apps/index.d.ts +2 -1
  45. package/dist/lib/apps/index.js +21 -4
  46. package/dist/lib/apps/paths.js +7 -6
  47. package/dist/lib/create/notification.d.ts +1 -0
  48. package/dist/lib/create/schemas.d.ts +1 -0
  49. package/dist/lib/create/schemas.js +1 -0
  50. package/dist/lib/create/setting.d.ts +15 -0
  51. package/dist/lib/create/setting.js +27 -0
  52. package/dist/lib/create/tests/templates/env-dts.d.ts +1 -0
  53. package/dist/lib/create/tests/templates/env-dts.js +15 -0
  54. package/dist/lib/create/tests/templates/index.d.ts +8 -0
  55. package/dist/lib/create/tests/templates/index.js +8 -0
  56. package/dist/lib/create/tests/templates/integration-test.d.ts +1 -0
  57. package/dist/lib/create/tests/templates/integration-test.js +19 -0
  58. package/dist/lib/create/tests/templates/mock-request.d.ts +2 -0
  59. package/dist/lib/create/tests/templates/mock-request.js +112 -0
  60. package/dist/lib/create/tests/templates/setup-globals.d.ts +1 -0
  61. package/dist/lib/create/tests/templates/setup-globals.js +23 -0
  62. package/dist/lib/create/tests/templates/swell-client.d.ts +1 -0
  63. package/dist/lib/create/tests/templates/swell-client.js +128 -0
  64. package/dist/lib/create/tests/templates/tsconfig.d.ts +1 -0
  65. package/dist/lib/create/tests/templates/tsconfig.js +17 -0
  66. package/dist/lib/create/tests/templates/unit-test.d.ts +1 -0
  67. package/dist/lib/create/tests/templates/unit-test.js +42 -0
  68. package/dist/lib/create/tests/templates/vitest-config.d.ts +2 -0
  69. package/dist/lib/create/tests/templates/vitest-config.js +122 -0
  70. package/dist/lib/create/tests/types.d.ts +21 -0
  71. package/dist/lib/create/tests/types.js +1 -0
  72. package/dist/lib/create/tests.d.ts +4 -0
  73. package/dist/lib/create/tests.js +113 -0
  74. package/dist/lib/create/webhook.d.ts +32 -0
  75. package/dist/lib/create/webhook.js +52 -0
  76. package/dist/swell-api-command.d.ts +14 -0
  77. package/dist/swell-api-command.js +113 -7
  78. package/oclif.manifest.json +2879 -0
  79. package/package.json +2 -1
@@ -46,6 +46,18 @@ const ConfigTypeBatchOrder = [
46
46
  ConfigType.FRONTEND,
47
47
  ConfigType.FILE,
48
48
  ];
49
+ // All available configs
50
+ const AllConfigTypes = [
51
+ 'ASSET',
52
+ 'CONTENT',
53
+ 'FRONTEND',
54
+ 'FUNCTION',
55
+ 'MODEL',
56
+ 'NOTIFICATION',
57
+ 'SETTING',
58
+ 'THEME',
59
+ 'WEBHOOK',
60
+ ];
49
61
  // Configs available for admin/integration app types
50
62
  const StandardConfigTypes = [
51
63
  'MODEL',
@@ -57,11 +69,13 @@ const StandardConfigTypes = [
57
69
  'SETTING',
58
70
  'WEBHOOK',
59
71
  ];
72
+ // Configs available for storefront app types
60
73
  export const StorefrontConfigTypes = [
61
74
  'FRONTEND',
62
75
  'ASSET',
63
76
  'SETTING',
64
77
  ];
78
+ // Configs available for theme types
65
79
  export const ThemeConfigTypes = ['THEME', 'ASSET'];
66
80
  const getConfigPaths = (types) =>
67
81
  // eslint-disable-next-line unicorn/no-array-reduce
@@ -76,7 +90,10 @@ Object.keys(ConfigType).reduce((acc, type) => {
76
90
  }
77
91
  return acc;
78
92
  }, {});
79
- export const ConfigPaths = {
93
+ export const AllConfigPaths = {
94
+ ...getConfigPaths(AllConfigTypes),
95
+ };
96
+ export const StandardConfigPaths = {
80
97
  ...getConfigPaths(StandardConfigTypes),
81
98
  };
82
99
  export const StorefrontConfigPaths = {
@@ -217,8 +234,8 @@ export function getFrontendProjectType(appPath) {
217
234
  return undefined;
218
235
  }
219
236
  export function getConfigTypeFromPath(path) {
220
- for (const type in ConfigPaths) {
221
- if (ConfigPaths[type] === path) {
237
+ for (const type in AllConfigPaths) {
238
+ if (AllConfigPaths[type] === path) {
222
239
  const configType = ConfigType[type];
223
240
  return configType;
224
241
  }
@@ -289,7 +306,7 @@ export function hashString(...contents) {
289
306
  return hash.digest('hex', { length: 16 });
290
307
  }
291
308
  export function appAssetImage(appPath, fileName) {
292
- const assetsDirPath = path.join(appPath, ConfigPaths['ASSET']);
309
+ const assetsDirPath = path.join(appPath, AllConfigPaths['ASSET']);
293
310
  if (!filePathExists(assetsDirPath)) {
294
311
  return;
295
312
  }
@@ -1,7 +1,7 @@
1
1
  import { globby, globbySync, isGitIgnored, } from 'globby';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
- import { ConfigPaths, ConfigType, StorefrontConfigPaths, ThemeConfigPaths, filePathExists, } from './index.js';
4
+ import { AllConfigPaths, ConfigType, StandardConfigPaths, StorefrontConfigPaths, ThemeConfigPaths, filePathExists, } from './index.js';
5
5
  function globOptions(appPath, options) {
6
6
  return {
7
7
  cwd: appPath,
@@ -35,7 +35,7 @@ export function getGlobIgnorePathsChecker(appPath) {
35
35
  function getConfigDirsPaths(appPath) {
36
36
  const configDirsPaths = [];
37
37
  for (const [type, configType] of Object.entries(ConfigType)) {
38
- const configPath = ConfigPaths[type];
38
+ const configPath = AllConfigPaths[type];
39
39
  if (!configPath) {
40
40
  continue;
41
41
  }
@@ -57,7 +57,7 @@ export function* allConfigFilesPaths(appPath) {
57
57
  }
58
58
  }
59
59
  export function* allConfigFilesPathsByType(appPath, configTypeKey) {
60
- const configPath = ConfigPaths[configTypeKey];
60
+ const configPath = AllConfigPaths[configTypeKey];
61
61
  yield* allConfigFilesInDir(appPath, configPath, ConfigType[configTypeKey]);
62
62
  }
63
63
  export function* allConfigFilesInDir(appPath, dirPath, configType) {
@@ -76,16 +76,17 @@ export function* allBaseFilesInDir(appPath) {
76
76
  yield path;
77
77
  }
78
78
  }
79
+ // this function is used to create folders for app
79
80
  export function getAllConfigPaths(appType) {
80
81
  const configPaths = [];
81
82
  const ConfigPathsByType = appType === 'storefront'
82
83
  ? StorefrontConfigPaths
83
84
  : appType === 'theme'
84
85
  ? ThemeConfigPaths
85
- : ConfigPaths;
86
+ : StandardConfigPaths;
86
87
  for (const type of Object.keys(ConfigPathsByType)) {
87
- if (Object.hasOwn(ConfigPaths, type)) {
88
- const configPath = ConfigPaths[type];
88
+ if (Object.hasOwn(AllConfigPaths, type)) {
89
+ const configPath = AllConfigPaths[type];
89
90
  configPaths.push(configPath);
90
91
  }
91
92
  }
@@ -8,6 +8,7 @@ interface WriteNotificationsFileParams {
8
8
  subject: string;
9
9
  }
10
10
  interface CreateNotificationFileBody {
11
+ $schema: string;
11
12
  admin?: boolean;
12
13
  collection: string;
13
14
  conditions: Record<any, any>;
@@ -3,4 +3,5 @@ export declare const SCHEMAS: {
3
3
  readonly MODEL: "https://json.swell.store/model.json";
4
4
  readonly NOTIFICATION: "https://json.swell.store/notification.json";
5
5
  readonly SETTING: "https://json.swell.store/setting.json";
6
+ readonly WEBHOOK: "https://json.swell.store/webhook.json";
6
7
  };
@@ -3,4 +3,5 @@ export const SCHEMAS = {
3
3
  MODEL: 'https://json.swell.store/model.json',
4
4
  NOTIFICATION: 'https://json.swell.store/notification.json',
5
5
  SETTING: 'https://json.swell.store/setting.json',
6
+ WEBHOOK: 'https://json.swell.store/webhook.json',
6
7
  };
@@ -0,0 +1,15 @@
1
+ interface CreateSettingFileBody {
2
+ $schema: string;
3
+ description?: string;
4
+ fields: SettingFieldProps[];
5
+ label?: string;
6
+ }
7
+ interface SettingFieldProps {
8
+ id: string;
9
+ label: string;
10
+ type?: SettingFieldType;
11
+ }
12
+ type SettingFieldType = 'asset' | 'basic_html' | 'boolean' | 'category_lookup' | 'checkbox' | 'checkboxes' | 'collection' | 'color' | 'color_scheme' | 'color_scheme_group' | 'currency' | 'customer_lookup' | 'date' | 'datetime' | 'document' | 'dropdown' | 'email' | 'field_group' | 'font_family' | 'generic_lookup' | 'html' | 'icon' | 'image' | 'long_text' | 'lookup' | 'markdown' | 'number' | 'percent' | 'phone' | 'product_lookup' | 'radio' | 'rich_html' | 'rich_text' | 'select' | 'short_text' | 'slider' | 'slug' | 'tags' | 'text' | 'textarea' | 'time' | 'toggle' | 'url' | 'variant_lookup' | 'video';
13
+ declare const parseFields: (fields: string[]) => SettingFieldProps[];
14
+ declare const toSettingLabel: (value: string) => string;
15
+ export { CreateSettingFileBody, parseFields, toSettingLabel };
@@ -0,0 +1,27 @@
1
+ import { titleize } from 'inflection';
2
+ const parseFields = (fields) => {
3
+ if (fields.length === 0) {
4
+ return [];
5
+ }
6
+ const fieldResponse = [];
7
+ for (const fieldPair of fields) {
8
+ if (fieldPair.includes(':')) {
9
+ const [id, type] = fieldPair.split(':');
10
+ fieldResponse.push({
11
+ id,
12
+ label: titleize(id),
13
+ type,
14
+ });
15
+ }
16
+ else {
17
+ fieldResponse.push({
18
+ id: fieldPair,
19
+ label: titleize(fieldPair),
20
+ });
21
+ }
22
+ }
23
+ return fieldResponse;
24
+ };
25
+ // Example: 'api-config' => 'Api Config'
26
+ const toSettingLabel = (value) => titleize(value).replaceAll('-', ' ');
27
+ export { parseFields, toSettingLabel };
@@ -0,0 +1 @@
1
+ export declare function envDtsTemplate(): string;
@@ -0,0 +1,15 @@
1
+ export function envDtsTemplate() {
2
+ return `\
3
+ declare module "cloudflare:test" {
4
+ interface ProvidedEnv {
5
+ SWELL_STORE_ID: string;
6
+ SWELL_SESSION_ID: string;
7
+ SWELL_API_BASE_URL: string;
8
+ SWELL_APP_ID: string;
9
+ SWELL_ENVIRONMENT?: string;
10
+ }
11
+ }
12
+
13
+ export {};
14
+ `;
15
+ }
@@ -0,0 +1,8 @@
1
+ export { envDtsTemplate } from './env-dts.js';
2
+ export { integrationTestTemplate } from './integration-test.js';
3
+ export { mockRequestTemplate } from './mock-request.js';
4
+ export { setupGlobalsTemplate } from './setup-globals.js';
5
+ export { swellClientTemplate } from './swell-client.js';
6
+ export { tsconfigTemplate } from './tsconfig.js';
7
+ export { unitTestTemplate } from './unit-test.js';
8
+ export { vitestConfigTemplate } from './vitest-config.js';
@@ -0,0 +1,8 @@
1
+ export { envDtsTemplate } from './env-dts.js';
2
+ export { integrationTestTemplate } from './integration-test.js';
3
+ export { mockRequestTemplate } from './mock-request.js';
4
+ export { setupGlobalsTemplate } from './setup-globals.js';
5
+ export { swellClientTemplate } from './swell-client.js';
6
+ export { tsconfigTemplate } from './tsconfig.js';
7
+ export { unitTestTemplate } from './unit-test.js';
8
+ export { vitestConfigTemplate } from './vitest-config.js';
@@ -0,0 +1 @@
1
+ export declare function integrationTestTemplate(): string;
@@ -0,0 +1,19 @@
1
+ export function integrationTestTemplate() {
2
+ return `\
3
+ import { describe, it, expect } from "vitest";
4
+ import { createSwellClient } from "../helpers/swell-client";
5
+
6
+ describe("Store settings (read-only)", () => {
7
+ it("loads general store settings using CLI auth", async () => {
8
+ const swell = createSwellClient();
9
+
10
+ const general = await swell.get("/settings/general");
11
+
12
+ expect(general).toBeDefined();
13
+ expect(general.id).toBe("general");
14
+ expect(general.features).toBeDefined();
15
+ expect(typeof general.features.carts).toBe("boolean");
16
+ });
17
+ });
18
+ `;
19
+ }
@@ -0,0 +1,2 @@
1
+ import type { TestTemplateOptions } from '../types.js';
2
+ export declare function mockRequestTemplate(options: TestTemplateOptions): string;
@@ -0,0 +1,112 @@
1
+ export function mockRequestTemplate(options) {
2
+ return `\
3
+ import { env } from "cloudflare:test";
4
+ import { createSwellClient } from "./swell-client";
5
+
6
+ export interface MockRequestOptions {
7
+ data?: SwellData;
8
+ query?: { [key: string]: string };
9
+ session?: { [key: string]: any };
10
+ headers?: Record<string, string>;
11
+ method?: string;
12
+ url?: string;
13
+ swell?: Partial<SwellAPI>;
14
+ store?: Partial<SwellStore>;
15
+ appId?: string;
16
+ useRealSwell?: boolean;
17
+ }
18
+
19
+ function createDefaultSwellMock(): Partial<SwellAPI> {
20
+ const notMocked = (method: string) => () => {
21
+ throw new Error(
22
+ \`swell.\${method}() not mocked. Pass { swell: { \${method}: vi.fn() } } to createMockRequest().\`
23
+ );
24
+ };
25
+ return {
26
+ get: notMocked("get"),
27
+ post: notMocked("post"),
28
+ put: notMocked("put"),
29
+ delete: notMocked("delete"),
30
+ settings: notMocked("settings"),
31
+ };
32
+ }
33
+
34
+ export function createMockRequest(options: MockRequestOptions = {}): SwellRequest {
35
+ const {
36
+ data = {},
37
+ query = {},
38
+ session = {},
39
+ headers = {},
40
+ method = "POST",
41
+ url = "https://example.com/test",
42
+ swell,
43
+ store,
44
+ appId,
45
+ useRealSwell = false,
46
+ } = options;
47
+
48
+ const requestHeaders = new Headers(headers);
49
+ const originalRequest = new Request(url, {
50
+ method,
51
+ headers: requestHeaders,
52
+ body: method === "GET" ? undefined : JSON.stringify(data),
53
+ });
54
+
55
+ const storeId = store?.id || env.SWELL_STORE_ID || "test-store";
56
+
57
+ const resolvedStore = {
58
+ id: storeId,
59
+ url: store?.url || "",
60
+ admin_url: store?.admin_url || "",
61
+ };
62
+
63
+ const context = {
64
+ waitUntil: async (promise: Promise<unknown>) => {
65
+ await promise;
66
+ },
67
+ };
68
+
69
+ const swellClient =
70
+ swell || (useRealSwell ? createSwellClient() : createDefaultSwellMock());
71
+
72
+ const resolvedAppId = appId || env.SWELL_APP_ID || "${options.appId}";
73
+
74
+ const req: Partial<SwellRequest> & { appId: string; storeId: string } = {
75
+ originalRequest,
76
+ context,
77
+ url,
78
+ method,
79
+ headers: requestHeaders,
80
+ referrer: originalRequest.referrer,
81
+ credentials: "include",
82
+ appId: resolvedAppId,
83
+ storeId,
84
+ accessToken: null,
85
+ publicKey: null,
86
+ store: resolvedStore,
87
+ session,
88
+ apiHost: env.SWELL_API_BASE_URL || "",
89
+ logParams: undefined,
90
+ swell: swellClient as SwellAPI,
91
+ body: data,
92
+ data,
93
+ query,
94
+ initialize: async () => {},
95
+ parseJson: (input: string) => JSON.parse(input),
96
+ appValues: (idOrValues: string | SwellData, values?: SwellData) => {
97
+ const targetAppId =
98
+ typeof idOrValues === "string" ? idOrValues : resolvedAppId;
99
+ const appValues = typeof idOrValues === "string" ? values : idOrValues;
100
+ if (!targetAppId || !appValues) return undefined;
101
+ return {
102
+ $app: {
103
+ [targetAppId]: appValues,
104
+ },
105
+ };
106
+ },
107
+ };
108
+
109
+ return req as SwellRequest;
110
+ }
111
+ `;
112
+ }
@@ -0,0 +1 @@
1
+ export declare function setupGlobalsTemplate(): string;
@@ -0,0 +1,23 @@
1
+ export function setupGlobalsTemplate() {
2
+ return `\
3
+ class SwellErrorImpl extends Error {
4
+ status: number;
5
+
6
+ constructor(message: string | object, options: { status?: number } = {}) {
7
+ const text =
8
+ typeof message === "string"
9
+ ? message
10
+ : JSON.stringify(message, null, 2);
11
+
12
+ super(text);
13
+ this.name = "SwellError";
14
+ this.status = options.status ?? 500;
15
+ }
16
+ }
17
+
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ (globalThis as any).SwellError = SwellErrorImpl;
20
+
21
+ export {};
22
+ `;
23
+ }
@@ -0,0 +1 @@
1
+ export declare function swellClientTemplate(): string;
@@ -0,0 +1,128 @@
1
+ export function swellClientTemplate() {
2
+ return `\
3
+ import { env } from "cloudflare:test";
4
+
5
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
6
+
7
+ type BasicSwellClient = Pick<
8
+ SwellAPI,
9
+ "get" | "post" | "put" | "delete" | "settings"
10
+ >;
11
+
12
+ async function makeRequest(
13
+ method: HttpMethod,
14
+ url: string,
15
+ data?: any
16
+ ): Promise<any> {
17
+ const baseUrl = env.SWELL_API_BASE_URL || "https://api.swell.store";
18
+ const sessionId = env.SWELL_SESSION_ID;
19
+ const environment = env.SWELL_ENVIRONMENT || "test";
20
+
21
+ if (!sessionId) {
22
+ throw new Error(
23
+ "Missing SWELL_SESSION_ID binding. Run \\\`swell login\\\` or set it explicitly for tests.",
24
+ );
25
+ }
26
+
27
+ let endpointUrl = String(url).startsWith("/") ? url.substring(1) : String(url);
28
+ if (!endpointUrl.startsWith("data/")) {
29
+ endpointUrl = \`data/\${endpointUrl}\`;
30
+ }
31
+
32
+ let fullUrl = \`\${baseUrl}/\${endpointUrl}\`;
33
+ const headers: HeadersInit = {
34
+ "Content-Type": "application/json;charset=UTF-8",
35
+ "User-Agent": "swell-app-tests/1.0",
36
+ "X-Session": sessionId,
37
+ "Swell-Env": environment,
38
+ };
39
+
40
+ const options: RequestInit = {
41
+ method,
42
+ headers,
43
+ };
44
+
45
+ if (data) {
46
+ if (method === "GET") {
47
+ const params = new URLSearchParams();
48
+
49
+ function append(prefix: string, value: any) {
50
+ if (value === null || value === undefined) return;
51
+ if (typeof value === "object" && !Array.isArray(value)) {
52
+ for (const [k, v] of Object.entries(value)) {
53
+ append(\`\${prefix}[\${k}]\`, v);
54
+ }
55
+ } else if (Array.isArray(value)) {
56
+ for (const v of value) {
57
+ append(\`\${prefix}[]\`, v);
58
+ }
59
+ } else {
60
+ params.append(prefix, String(value));
61
+ }
62
+ }
63
+
64
+ for (const [key, value] of Object.entries(data)) {
65
+ append(key, value);
66
+ }
67
+
68
+ const query = params.toString();
69
+ if (query) {
70
+ fullUrl += \`?\${query}\`;
71
+ }
72
+ } else {
73
+ options.body = JSON.stringify(data);
74
+ }
75
+ }
76
+
77
+ const response = await fetch(fullUrl, options);
78
+ const text = await response.text();
79
+
80
+ let result: any;
81
+ try {
82
+ result = text ? JSON.parse(text) : null;
83
+ } catch {
84
+ result = text;
85
+ }
86
+
87
+ if (!response.ok) {
88
+ throw new (globalThis as any).SwellError(result || text || "Request failed", {
89
+ status: response.status,
90
+ });
91
+ }
92
+
93
+ if (result?.errors) {
94
+ throw new (globalThis as any).SwellError(result.errors, {
95
+ status: 400,
96
+ });
97
+ }
98
+
99
+ return result;
100
+ }
101
+
102
+ export function createSwellClient(): BasicSwellClient {
103
+ return {
104
+ get(url: string, query?: any) {
105
+ return makeRequest("GET", url, query);
106
+ },
107
+ post(url: string, data?: any) {
108
+ return makeRequest("POST", url, data);
109
+ },
110
+ put(url: string, data?: any) {
111
+ return makeRequest("PUT", url, data);
112
+ },
113
+ delete(url: string, data?: any) {
114
+ return makeRequest("DELETE", url, data);
115
+ },
116
+ settings(id?: string) {
117
+ const appId = id || env.SWELL_APP_ID;
118
+ if (!appId) {
119
+ throw new Error(
120
+ "Missing app id. Pass an id to settings() or set SWELL_APP_ID binding.",
121
+ );
122
+ }
123
+ return makeRequest("GET", \`/settings/\${appId}\`);
124
+ },
125
+ } as BasicSwellClient;
126
+ }
127
+ `;
128
+ }
@@ -0,0 +1 @@
1
+ export declare function tsconfigTemplate(): string;
@@ -0,0 +1,17 @@
1
+ export function tsconfigTemplate() {
2
+ const config = {
3
+ extends: '../tsconfig.json',
4
+ compilerOptions: {
5
+ moduleResolution: 'bundler',
6
+ skipLibCheck: true,
7
+ types: [
8
+ '@cloudflare/vitest-pool-workers',
9
+ '@swell/app-types',
10
+ 'vitest/globals',
11
+ ],
12
+ },
13
+ include: ['./**/*.ts', '../functions/**/*.ts'],
14
+ exclude: ['../node_modules'],
15
+ };
16
+ return `${JSON.stringify(config, null, 2)}\n`;
17
+ }
@@ -0,0 +1 @@
1
+ export declare function unitTestTemplate(): string;
@@ -0,0 +1,42 @@
1
+ export function unitTestTemplate() {
2
+ return `\
3
+ import { describe, it, expect, vi } from "vitest";
4
+ import { createMockRequest } from "../helpers/mock-request";
5
+
6
+ // Import your functions to test:
7
+ // import handler from "../../functions/my-handler";
8
+
9
+ describe("Unit test examples", () => {
10
+ it("creates a mock request with data and session", () => {
11
+ const req = createMockRequest({
12
+ data: { product_id: "prod_123" },
13
+ session: { account_id: "acc_456" },
14
+ });
15
+
16
+ expect(req.data.product_id).toBe("prod_123");
17
+ expect(req.session.account_id).toBe("acc_456");
18
+ });
19
+
20
+ it("mocks swell.get", async () => {
21
+ const mockGet = vi.fn().mockResolvedValue({ id: "123", name: "Test" });
22
+ const req = createMockRequest({ swell: { get: mockGet } });
23
+
24
+ const result = await req.swell.get("/products/{id}", { id: "123" });
25
+
26
+ expect(result.name).toBe("Test");
27
+ expect(mockGet).toHaveBeenCalledWith("/products/{id}", { id: "123" });
28
+ });
29
+
30
+ it("mocks swell.settings", async () => {
31
+ const mockSettings = vi.fn().mockResolvedValue({
32
+ feature: { enabled: true },
33
+ });
34
+ const req = createMockRequest({ swell: { settings: mockSettings } });
35
+
36
+ const settings = await req.swell.settings();
37
+
38
+ expect(settings.feature.enabled).toBe(true);
39
+ });
40
+ });
41
+ `;
42
+ }
@@ -0,0 +1,2 @@
1
+ import type { TestTemplateOptions } from '../types.js';
2
+ export declare function vitestConfigTemplate(options: TestTemplateOptions): string;