@codaijs/keel 0.1.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.
- package/dist/__tests__/cli.test.d.ts +2 -0
- package/dist/__tests__/cli.test.d.ts.map +1 -0
- package/dist/__tests__/cli.test.js +173 -0
- package/dist/__tests__/cli.test.js.map +1 -0
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +86 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/sail-installer.test.d.ts +2 -0
- package/dist/__tests__/sail-installer.test.d.ts.map +1 -0
- package/dist/__tests__/sail-installer.test.js +158 -0
- package/dist/__tests__/sail-installer.test.js.map +1 -0
- package/dist/create-runner.d.ts +11 -0
- package/dist/create-runner.d.ts.map +1 -0
- package/dist/create-runner.js +63 -0
- package/dist/create-runner.js.map +1 -0
- package/dist/create.d.ts +10 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +15 -0
- package/dist/create.js.map +1 -0
- package/dist/manage.d.ts +24 -0
- package/dist/manage.d.ts.map +1 -0
- package/dist/manage.js +1461 -0
- package/dist/manage.js.map +1 -0
- package/dist/prompts.d.ts +36 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +208 -0
- package/dist/prompts.js.map +1 -0
- package/dist/sail-installer.d.ts +37 -0
- package/dist/sail-installer.d.ts.map +1 -0
- package/dist/sail-installer.js +935 -0
- package/dist/sail-installer.js.map +1 -0
- package/dist/scaffold.d.ts +10 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +297 -0
- package/dist/scaffold.js.map +1 -0
- package/package.json +57 -0
- package/sails/_template/addon.json +20 -0
- package/sails/_template/install.ts +402 -0
- package/sails/admin-dashboard/README.md +117 -0
- package/sails/admin-dashboard/addon.json +28 -0
- package/sails/admin-dashboard/files/backend/middleware/admin.ts +34 -0
- package/sails/admin-dashboard/files/backend/routes/admin.ts +243 -0
- package/sails/admin-dashboard/files/frontend/components/admin/StatsCard.tsx +40 -0
- package/sails/admin-dashboard/files/frontend/components/admin/UsersTable.tsx +240 -0
- package/sails/admin-dashboard/files/frontend/hooks/useAdmin.ts +149 -0
- package/sails/admin-dashboard/files/frontend/pages/admin/Dashboard.tsx +173 -0
- package/sails/admin-dashboard/files/frontend/pages/admin/UserDetail.tsx +203 -0
- package/sails/admin-dashboard/install.ts +305 -0
- package/sails/analytics/README.md +178 -0
- package/sails/analytics/addon.json +27 -0
- package/sails/analytics/files/frontend/components/AnalyticsProvider.tsx +58 -0
- package/sails/analytics/files/frontend/hooks/useAnalytics.ts +64 -0
- package/sails/analytics/files/frontend/lib/analytics.ts +103 -0
- package/sails/analytics/install.ts +297 -0
- package/sails/file-uploads/README.md +191 -0
- package/sails/file-uploads/addon.json +30 -0
- package/sails/file-uploads/files/backend/routes/files.ts +198 -0
- package/sails/file-uploads/files/backend/schema/files.ts +36 -0
- package/sails/file-uploads/files/backend/services/file-storage.ts +128 -0
- package/sails/file-uploads/files/frontend/components/FileList.tsx +248 -0
- package/sails/file-uploads/files/frontend/components/FileUploadButton.tsx +147 -0
- package/sails/file-uploads/files/frontend/hooks/useFileUpload.ts +106 -0
- package/sails/file-uploads/files/frontend/hooks/useFiles.ts +118 -0
- package/sails/file-uploads/files/frontend/pages/Files.tsx +37 -0
- package/sails/file-uploads/install.ts +466 -0
- package/sails/gdpr/README.md +174 -0
- package/sails/gdpr/addon.json +27 -0
- package/sails/gdpr/files/backend/routes/gdpr.ts +140 -0
- package/sails/gdpr/files/backend/services/gdpr.ts +293 -0
- package/sails/gdpr/files/frontend/components/auth/ConsentCheckboxes.tsx +97 -0
- package/sails/gdpr/files/frontend/components/gdpr/AccountDeletionRequest.tsx +192 -0
- package/sails/gdpr/files/frontend/components/gdpr/DataExportButton.tsx +75 -0
- package/sails/gdpr/files/frontend/pages/PrivacyPolicy.tsx +186 -0
- package/sails/gdpr/install.ts +756 -0
- package/sails/google-oauth/README.md +121 -0
- package/sails/google-oauth/addon.json +22 -0
- package/sails/google-oauth/files/GoogleButton.tsx +50 -0
- package/sails/google-oauth/install.ts +252 -0
- package/sails/i18n/README.md +193 -0
- package/sails/i18n/addon.json +30 -0
- package/sails/i18n/files/frontend/components/LanguageSwitcher.tsx +108 -0
- package/sails/i18n/files/frontend/hooks/useLanguage.ts +31 -0
- package/sails/i18n/files/frontend/lib/i18n.ts +32 -0
- package/sails/i18n/files/frontend/locales/de/common.json +44 -0
- package/sails/i18n/files/frontend/locales/en/common.json +44 -0
- package/sails/i18n/install.ts +407 -0
- package/sails/push-notifications/README.md +163 -0
- package/sails/push-notifications/addon.json +31 -0
- package/sails/push-notifications/files/backend/routes/notifications.ts +153 -0
- package/sails/push-notifications/files/backend/schema/notifications.ts +31 -0
- package/sails/push-notifications/files/backend/services/notifications.ts +117 -0
- package/sails/push-notifications/files/frontend/components/PushNotificationInit.tsx +12 -0
- package/sails/push-notifications/files/frontend/hooks/usePushNotifications.ts +154 -0
- package/sails/push-notifications/install.ts +384 -0
- package/sails/r2-storage/README.md +101 -0
- package/sails/r2-storage/addon.json +29 -0
- package/sails/r2-storage/files/backend/services/storage.ts +71 -0
- package/sails/r2-storage/files/frontend/components/ProfilePictureUpload.tsx +167 -0
- package/sails/r2-storage/install.ts +412 -0
- package/sails/rate-limiting/README.md +145 -0
- package/sails/rate-limiting/addon.json +20 -0
- package/sails/rate-limiting/files/backend/middleware/rate-limit-store.ts +104 -0
- package/sails/rate-limiting/files/backend/middleware/rate-limit.ts +137 -0
- package/sails/rate-limiting/install.ts +300 -0
- package/sails/registry.json +107 -0
- package/sails/stripe/README.md +214 -0
- package/sails/stripe/addon.json +24 -0
- package/sails/stripe/files/backend/routes/stripe.ts +154 -0
- package/sails/stripe/files/backend/schema/stripe.ts +74 -0
- package/sails/stripe/files/backend/services/stripe.ts +224 -0
- package/sails/stripe/files/frontend/components/SubscriptionStatus.tsx +135 -0
- package/sails/stripe/files/frontend/hooks/useSubscription.ts +86 -0
- package/sails/stripe/files/frontend/pages/Checkout.tsx +116 -0
- package/sails/stripe/files/frontend/pages/Pricing.tsx +226 -0
- package/sails/stripe/install.ts +378 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
// Mock the interactive prompts since we're testing flag parsing
|
|
3
|
+
vi.mock("@inquirer/prompts", () => ({
|
|
4
|
+
input: vi.fn(),
|
|
5
|
+
select: vi.fn(),
|
|
6
|
+
checkbox: vi.fn(),
|
|
7
|
+
confirm: vi.fn(),
|
|
8
|
+
}));
|
|
9
|
+
const { parseFlags, runPrompts } = await import("../prompts.js");
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// parseFlags
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
describe("parseFlags", () => {
|
|
14
|
+
it("parses --yes flag", () => {
|
|
15
|
+
const { flags } = parseFlags(["--yes"]);
|
|
16
|
+
expect(flags.yes).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
it("parses -y shorthand", () => {
|
|
19
|
+
const { flags } = parseFlags(["-y"]);
|
|
20
|
+
expect(flags.yes).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
it("extracts project name from positional arg", () => {
|
|
23
|
+
const { projectName, flags } = parseFlags(["my-app"]);
|
|
24
|
+
expect(projectName).toBe("my-app");
|
|
25
|
+
expect(flags.yes).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it("parses --db=docker", () => {
|
|
28
|
+
const { flags } = parseFlags(["--db=docker"]);
|
|
29
|
+
expect(flags.db).toBe("docker");
|
|
30
|
+
});
|
|
31
|
+
it("parses --db=url", () => {
|
|
32
|
+
const { flags } = parseFlags(["--db=url"]);
|
|
33
|
+
expect(flags.db).toBe("url");
|
|
34
|
+
});
|
|
35
|
+
it("parses --db=skip", () => {
|
|
36
|
+
const { flags } = parseFlags(["--db=skip"]);
|
|
37
|
+
expect(flags.db).toBe("skip");
|
|
38
|
+
});
|
|
39
|
+
it("parses --db-url and sets db=url", () => {
|
|
40
|
+
const { flags } = parseFlags(["--db-url=postgresql://localhost/mydb"]);
|
|
41
|
+
expect(flags.db).toBe("url");
|
|
42
|
+
expect(flags.dbUrl).toBe("postgresql://localhost/mydb");
|
|
43
|
+
});
|
|
44
|
+
it("parses --resend-key", () => {
|
|
45
|
+
const { flags } = parseFlags(["--resend-key=re_test_abc"]);
|
|
46
|
+
expect(flags.resendKey).toBe("re_test_abc");
|
|
47
|
+
});
|
|
48
|
+
it("parses --email-from", () => {
|
|
49
|
+
const { flags } = parseFlags(["--email-from=noreply@example.com"]);
|
|
50
|
+
expect(flags.emailFrom).toBe("noreply@example.com");
|
|
51
|
+
});
|
|
52
|
+
it("parses --sails with comma-separated values", () => {
|
|
53
|
+
const { flags } = parseFlags(["--sails=stripe,google-oauth"]);
|
|
54
|
+
expect(flags.sails).toEqual(["stripe", "google-oauth"]);
|
|
55
|
+
});
|
|
56
|
+
it("parses --sails with single value", () => {
|
|
57
|
+
const { flags } = parseFlags(["--sails=stripe"]);
|
|
58
|
+
expect(flags.sails).toEqual(["stripe"]);
|
|
59
|
+
});
|
|
60
|
+
it("parses combined flags", () => {
|
|
61
|
+
const { projectName, flags } = parseFlags([
|
|
62
|
+
"my-app",
|
|
63
|
+
"--yes",
|
|
64
|
+
"--db=docker",
|
|
65
|
+
"--sails=stripe,google-oauth",
|
|
66
|
+
"--resend-key=re_test",
|
|
67
|
+
"--email-from=noreply@x.com",
|
|
68
|
+
]);
|
|
69
|
+
expect(projectName).toBe("my-app");
|
|
70
|
+
expect(flags.yes).toBe(true);
|
|
71
|
+
expect(flags.db).toBe("docker");
|
|
72
|
+
expect(flags.sails).toEqual(["stripe", "google-oauth"]);
|
|
73
|
+
expect(flags.resendKey).toBe("re_test");
|
|
74
|
+
expect(flags.emailFrom).toBe("noreply@x.com");
|
|
75
|
+
});
|
|
76
|
+
it("ignores unknown flags gracefully", () => {
|
|
77
|
+
const { flags } = parseFlags(["--unknown-flag=value", "--yes"]);
|
|
78
|
+
expect(flags.yes).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
it("returns empty flags for empty args", () => {
|
|
81
|
+
const { projectName, flags } = parseFlags([]);
|
|
82
|
+
expect(projectName).toBeUndefined();
|
|
83
|
+
expect(flags.yes).toBe(false);
|
|
84
|
+
expect(flags.db).toBeUndefined();
|
|
85
|
+
expect(flags.sails).toBeUndefined();
|
|
86
|
+
});
|
|
87
|
+
it("filters empty strings from sails", () => {
|
|
88
|
+
const { flags } = parseFlags(["--sails=,"]);
|
|
89
|
+
expect(flags.sails).toEqual([]);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// runPrompts (non-interactive / --yes mode)
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
describe("runPrompts with --yes flag", () => {
|
|
96
|
+
it("returns default config with --yes and no project name", async () => {
|
|
97
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
98
|
+
const config = await runPrompts(undefined, { yes: true });
|
|
99
|
+
expect(config.projectName).toBe("my-app");
|
|
100
|
+
expect(config.displayName).toBe("My App");
|
|
101
|
+
expect(config.description).toBe("My App — built with keel");
|
|
102
|
+
expect(config.databaseSetup).toBe("docker");
|
|
103
|
+
expect(config.databaseUrl).toContain("postgresql://");
|
|
104
|
+
expect(config.databaseUrl).toContain("my_app");
|
|
105
|
+
expect(config.resendApiKey).toBe("");
|
|
106
|
+
expect(config.emailFrom).toBe("");
|
|
107
|
+
expect(config.betterAuthSecret).toBeTruthy();
|
|
108
|
+
expect(config.betterAuthSecret.length).toBeGreaterThan(0);
|
|
109
|
+
expect(config.sails).toEqual([]);
|
|
110
|
+
consoleSpy.mockRestore();
|
|
111
|
+
});
|
|
112
|
+
it("uses provided project name with --yes", async () => {
|
|
113
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
114
|
+
const config = await runPrompts("cool-project", { yes: true });
|
|
115
|
+
expect(config.projectName).toBe("cool-project");
|
|
116
|
+
expect(config.displayName).toBe("Cool Project");
|
|
117
|
+
expect(config.databaseUrl).toContain("cool_project");
|
|
118
|
+
consoleSpy.mockRestore();
|
|
119
|
+
});
|
|
120
|
+
it("sanitizes project name", async () => {
|
|
121
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
122
|
+
const config = await runPrompts("My Cool App!", { yes: true });
|
|
123
|
+
// sanitize: lowercase -> replace non-alnum with - -> strip leading/trailing -
|
|
124
|
+
expect(config.projectName).toBe("my-cool-app");
|
|
125
|
+
consoleSpy.mockRestore();
|
|
126
|
+
});
|
|
127
|
+
it("uses provided flags", async () => {
|
|
128
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
129
|
+
const config = await runPrompts("test-proj", {
|
|
130
|
+
yes: true,
|
|
131
|
+
db: "url",
|
|
132
|
+
dbUrl: "postgresql://custom:pass@host/db",
|
|
133
|
+
resendKey: "re_test",
|
|
134
|
+
emailFrom: "hello@example.com",
|
|
135
|
+
sails: ["stripe", "google-oauth"],
|
|
136
|
+
});
|
|
137
|
+
expect(config.databaseSetup).toBe("url");
|
|
138
|
+
expect(config.databaseUrl).toBe("postgresql://custom:pass@host/db");
|
|
139
|
+
expect(config.resendApiKey).toBe("re_test");
|
|
140
|
+
expect(config.emailFrom).toBe("hello@example.com");
|
|
141
|
+
expect(config.sails).toEqual(["stripe", "google-oauth"]);
|
|
142
|
+
consoleSpy.mockRestore();
|
|
143
|
+
});
|
|
144
|
+
it("generates a unique betterAuthSecret each time", async () => {
|
|
145
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
146
|
+
const config1 = await runPrompts("app1", { yes: true });
|
|
147
|
+
const config2 = await runPrompts("app2", { yes: true });
|
|
148
|
+
expect(config1.betterAuthSecret).not.toBe(config2.betterAuthSecret);
|
|
149
|
+
// Should be a hex string (64 chars for 32 bytes)
|
|
150
|
+
expect(config1.betterAuthSecret).toMatch(/^[a-f0-9]{64}$/);
|
|
151
|
+
consoleSpy.mockRestore();
|
|
152
|
+
});
|
|
153
|
+
it("constructs docker database URL from project name", async () => {
|
|
154
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
155
|
+
const config = await runPrompts("my-cool-app", {
|
|
156
|
+
yes: true,
|
|
157
|
+
db: "docker",
|
|
158
|
+
});
|
|
159
|
+
expect(config.databaseUrl).toBe("postgresql://postgres:postgres@localhost:5432/my_cool_app");
|
|
160
|
+
consoleSpy.mockRestore();
|
|
161
|
+
});
|
|
162
|
+
it("handles skip database setup", async () => {
|
|
163
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
164
|
+
const config = await runPrompts("test", {
|
|
165
|
+
yes: true,
|
|
166
|
+
db: "skip",
|
|
167
|
+
});
|
|
168
|
+
expect(config.databaseSetup).toBe("skip");
|
|
169
|
+
expect(config.databaseUrl).toBe("");
|
|
170
|
+
consoleSpy.mockRestore();
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=cli.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.test.js","sourceRoot":"","sources":["../../src/__tests__/cli.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAElD,gEAAgE;AAChE,EAAE,CAAC,IAAI,CAAC,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;IACd,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE;IACf,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;IACjB,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE;CACjB,CAAC,CAAC,CAAC;AAEJ,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;AAEjE,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC;YACxC,QAAQ;YACR,OAAO;YACP,aAAa;YACb,6BAA6B;YAC7B,sBAAsB;YACtB,4BAA4B;SAC7B,CAAC,CAAC;QAEH,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,CAAC,WAAW,CAAC,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,4CAA4C;AAC5C,8EAA8E;AAE9E,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1D,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;QACtD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,UAAU,EAAE,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEjC,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAErD,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,8EAA8E;QAC9E,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAE/C,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,WAAW,EAAE;YAC3C,GAAG,EAAE,IAAI;YACT,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,kCAAkC;YACzC,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,mBAAmB;YAC9B,KAAK,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC;SAClC,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;QAEzD,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;QAExD,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACpE,iDAAiD;QACjD,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAE3D,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,aAAa,EAAE;YAC7C,GAAG,EAAE,IAAI;YACT,EAAE,EAAE,QAAQ;SACb,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAC7B,2DAA2D,CAC5D,CAAC;QAEF,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,UAAU,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE;YACtC,GAAG,EAAE,IAAI;YACT,EAAE,EAAE,MAAM;SACX,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEpC,UAAU,CAAC,WAAW,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const SAILS_DIR = join(__dirname, "..", "..", "sails");
|
|
7
|
+
const REGISTRY_PATH = join(SAILS_DIR, "registry.json");
|
|
8
|
+
describe("sail registry", () => {
|
|
9
|
+
it("registry.json exists and is valid JSON", () => {
|
|
10
|
+
expect(existsSync(REGISTRY_PATH)).toBe(true);
|
|
11
|
+
const content = readFileSync(REGISTRY_PATH, "utf-8");
|
|
12
|
+
const registry = JSON.parse(content);
|
|
13
|
+
expect(registry).toBeDefined();
|
|
14
|
+
expect(registry.version).toBeDefined();
|
|
15
|
+
expect(Array.isArray(registry.sails)).toBe(true);
|
|
16
|
+
});
|
|
17
|
+
it("each sail has required fields", () => {
|
|
18
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
19
|
+
for (const sail of registry.sails) {
|
|
20
|
+
expect(sail.name).toBeTruthy();
|
|
21
|
+
expect(sail.displayName).toBeTruthy();
|
|
22
|
+
expect(sail.description).toBeTruthy();
|
|
23
|
+
expect(sail.category).toBeTruthy();
|
|
24
|
+
expect(sail.version).toBeTruthy();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it("sail names are unique", () => {
|
|
28
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
29
|
+
const names = registry.sails.map((s) => s.name);
|
|
30
|
+
const uniqueNames = new Set(names);
|
|
31
|
+
expect(uniqueNames.size).toBe(names.length);
|
|
32
|
+
});
|
|
33
|
+
it("non-planned sails have an addon.json manifest", () => {
|
|
34
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
35
|
+
const availableSails = registry.sails.filter((s) => s.status !== "planned");
|
|
36
|
+
for (const sail of availableSails) {
|
|
37
|
+
const manifestPath = join(SAILS_DIR, sail.name, "addon.json");
|
|
38
|
+
expect(existsSync(manifestPath), `Missing addon.json for sail: ${sail.name}`).toBe(true);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
it("non-planned sails have an install.ts file", () => {
|
|
42
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
43
|
+
const availableSails = registry.sails.filter((s) => s.status !== "planned");
|
|
44
|
+
for (const sail of availableSails) {
|
|
45
|
+
const installPath = join(SAILS_DIR, sail.name, "install.ts");
|
|
46
|
+
expect(existsSync(installPath), `Missing install.ts for sail: ${sail.name}`).toBe(true);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
it("addon.json manifests have valid structure", () => {
|
|
50
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
51
|
+
const availableSails = registry.sails.filter((s) => s.status !== "planned");
|
|
52
|
+
for (const sail of availableSails) {
|
|
53
|
+
const manifestPath = join(SAILS_DIR, sail.name, "addon.json");
|
|
54
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
55
|
+
expect(manifest.name).toBe(sail.name);
|
|
56
|
+
expect(manifest.displayName).toBeTruthy();
|
|
57
|
+
expect(manifest.version).toBeTruthy();
|
|
58
|
+
expect(manifest.dependencies).toBeDefined();
|
|
59
|
+
expect(manifest.dependencies.backend).toBeDefined();
|
|
60
|
+
expect(manifest.dependencies.frontend).toBeDefined();
|
|
61
|
+
expect(manifest.modifies).toBeDefined();
|
|
62
|
+
expect(manifest.adds).toBeDefined();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
it("contains the expected core sails", () => {
|
|
66
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
67
|
+
const sailNames = registry.sails.map((s) => s.name);
|
|
68
|
+
expect(sailNames).toContain("google-oauth");
|
|
69
|
+
expect(sailNames).toContain("stripe");
|
|
70
|
+
expect(sailNames).toContain("gdpr");
|
|
71
|
+
expect(sailNames).toContain("r2-storage");
|
|
72
|
+
expect(sailNames).toContain("push-notifications");
|
|
73
|
+
expect(sailNames).toContain("analytics");
|
|
74
|
+
expect(sailNames).toContain("admin-dashboard");
|
|
75
|
+
expect(sailNames).toContain("i18n");
|
|
76
|
+
});
|
|
77
|
+
it("planned sails are correctly marked", () => {
|
|
78
|
+
const registry = JSON.parse(readFileSync(REGISTRY_PATH, "utf-8"));
|
|
79
|
+
const plannedSails = registry.sails.filter((s) => s.status === "planned");
|
|
80
|
+
// Based on the current registry, rate-limiting and file-uploads are planned
|
|
81
|
+
const plannedNames = plannedSails.map((s) => s.name);
|
|
82
|
+
expect(plannedNames).toContain("rate-limiting");
|
|
83
|
+
expect(plannedNames).toContain("file-uploads");
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sail-installer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sail-installer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, rmSync, } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Test insertAtMarker directly (exported function)
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// We need to mock chalk and ora to avoid terminal output during tests
|
|
9
|
+
vi.mock("chalk", () => ({
|
|
10
|
+
default: {
|
|
11
|
+
yellow: (s) => s,
|
|
12
|
+
cyan: (s) => s,
|
|
13
|
+
bold: (s) => s,
|
|
14
|
+
white: (s) => s,
|
|
15
|
+
green: (s) => s,
|
|
16
|
+
red: (s) => s,
|
|
17
|
+
gray: (s) => s,
|
|
18
|
+
},
|
|
19
|
+
}));
|
|
20
|
+
vi.mock("ora", () => ({
|
|
21
|
+
default: () => ({
|
|
22
|
+
start: vi.fn().mockReturnThis(),
|
|
23
|
+
succeed: vi.fn().mockReturnThis(),
|
|
24
|
+
fail: vi.fn().mockReturnThis(),
|
|
25
|
+
warn: vi.fn().mockReturnThis(),
|
|
26
|
+
}),
|
|
27
|
+
}));
|
|
28
|
+
const { insertAtMarker, getManualSteps } = await import("../sail-installer.js");
|
|
29
|
+
describe("insertAtMarker", () => {
|
|
30
|
+
let tempDir;
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
tempDir = join(tmpdir(), `keel-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
33
|
+
mkdirSync(tempDir, { recursive: true });
|
|
34
|
+
// Clear manual steps
|
|
35
|
+
getManualSteps();
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
39
|
+
});
|
|
40
|
+
it("inserts code after marker comment", () => {
|
|
41
|
+
const filePath = join(tempDir, "test.ts");
|
|
42
|
+
writeFileSync(filePath, `import express from "express";
|
|
43
|
+
// [SAIL_IMPORTS]
|
|
44
|
+
|
|
45
|
+
const app = express();
|
|
46
|
+
// [SAIL_ROUTES]
|
|
47
|
+
|
|
48
|
+
app.listen(3000);
|
|
49
|
+
`);
|
|
50
|
+
const result = insertAtMarker(filePath, "// [SAIL_IMPORTS]", 'import { stripeRouter } from "./routes/stripe.js";');
|
|
51
|
+
expect(result).toBe(true);
|
|
52
|
+
const content = readFileSync(filePath, "utf-8");
|
|
53
|
+
expect(content).toContain('import { stripeRouter } from "./routes/stripe.js";');
|
|
54
|
+
// The import should appear after the marker
|
|
55
|
+
const markerIndex = content.indexOf("// [SAIL_IMPORTS]");
|
|
56
|
+
const importIndex = content.indexOf('import { stripeRouter }');
|
|
57
|
+
expect(importIndex).toBeGreaterThan(markerIndex);
|
|
58
|
+
});
|
|
59
|
+
it("inserts code after JSX marker comment", () => {
|
|
60
|
+
const filePath = join(tempDir, "router.tsx");
|
|
61
|
+
writeFileSync(filePath, `<Route path="/" element={<Home />} />
|
|
62
|
+
{/* [SAIL_ROUTES] */}
|
|
63
|
+
</Route>
|
|
64
|
+
`);
|
|
65
|
+
const result = insertAtMarker(filePath, "{/* [SAIL_ROUTES] */}", ' <Route path="/pricing" element={<Pricing />} />');
|
|
66
|
+
expect(result).toBe(true);
|
|
67
|
+
const content = readFileSync(filePath, "utf-8");
|
|
68
|
+
expect(content).toContain('<Route path="/pricing" element={<Pricing />} />');
|
|
69
|
+
});
|
|
70
|
+
it("is idempotent — does not insert the same code twice", () => {
|
|
71
|
+
const filePath = join(tempDir, "test.ts");
|
|
72
|
+
const originalContent = `// [SAIL_IMPORTS]
|
|
73
|
+
const x = 1;
|
|
74
|
+
`;
|
|
75
|
+
writeFileSync(filePath, originalContent);
|
|
76
|
+
const code = 'import { foo } from "./foo.js";';
|
|
77
|
+
// First insertion
|
|
78
|
+
insertAtMarker(filePath, "// [SAIL_IMPORTS]", code);
|
|
79
|
+
const afterFirst = readFileSync(filePath, "utf-8");
|
|
80
|
+
// Second insertion — should be a no-op
|
|
81
|
+
insertAtMarker(filePath, "// [SAIL_IMPORTS]", code);
|
|
82
|
+
const afterSecond = readFileSync(filePath, "utf-8");
|
|
83
|
+
expect(afterFirst).toBe(afterSecond);
|
|
84
|
+
// Count occurrences of the code
|
|
85
|
+
const matches = afterSecond.match(/import \{ foo \}/g);
|
|
86
|
+
expect(matches?.length).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
it("records manual step when marker is missing", () => {
|
|
89
|
+
const filePath = join(tempDir, "test.ts");
|
|
90
|
+
writeFileSync(filePath, `import express from "express";
|
|
91
|
+
const app = express();
|
|
92
|
+
`);
|
|
93
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
94
|
+
const result = insertAtMarker(filePath, "// [SAIL_IMPORTS]", 'import { foo } from "./foo.js";');
|
|
95
|
+
expect(result).toBe(false);
|
|
96
|
+
const steps = getManualSteps();
|
|
97
|
+
expect(steps.length).toBeGreaterThan(0);
|
|
98
|
+
expect(steps[0]).toContain('import { foo } from "./foo.js";');
|
|
99
|
+
consoleSpy.mockRestore();
|
|
100
|
+
});
|
|
101
|
+
it("records manual step when file does not exist", () => {
|
|
102
|
+
const filePath = join(tempDir, "nonexistent.ts");
|
|
103
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
104
|
+
const result = insertAtMarker(filePath, "// [SAIL_IMPORTS]", 'import { foo } from "./foo.js";');
|
|
105
|
+
expect(result).toBe(false);
|
|
106
|
+
const steps = getManualSteps();
|
|
107
|
+
expect(steps.length).toBeGreaterThan(0);
|
|
108
|
+
consoleSpy.mockRestore();
|
|
109
|
+
});
|
|
110
|
+
it("preserves existing content around marker", () => {
|
|
111
|
+
const filePath = join(tempDir, "test.ts");
|
|
112
|
+
writeFileSync(filePath, `line1
|
|
113
|
+
// [SAIL_IMPORTS]
|
|
114
|
+
line3
|
|
115
|
+
line4
|
|
116
|
+
`);
|
|
117
|
+
insertAtMarker(filePath, "// [SAIL_IMPORTS]", "inserted_line");
|
|
118
|
+
const content = readFileSync(filePath, "utf-8");
|
|
119
|
+
expect(content).toContain("line1");
|
|
120
|
+
expect(content).toContain("// [SAIL_IMPORTS]");
|
|
121
|
+
expect(content).toContain("inserted_line");
|
|
122
|
+
expect(content).toContain("line3");
|
|
123
|
+
expect(content).toContain("line4");
|
|
124
|
+
});
|
|
125
|
+
it("handles multiple markers in same file", () => {
|
|
126
|
+
const filePath = join(tempDir, "test.ts");
|
|
127
|
+
writeFileSync(filePath, `// [SAIL_IMPORTS]
|
|
128
|
+
|
|
129
|
+
const app = express();
|
|
130
|
+
|
|
131
|
+
// [SAIL_ROUTES]
|
|
132
|
+
|
|
133
|
+
app.listen(3000);
|
|
134
|
+
`);
|
|
135
|
+
insertAtMarker(filePath, "// [SAIL_IMPORTS]", 'import { a } from "./a.js";');
|
|
136
|
+
insertAtMarker(filePath, "// [SAIL_ROUTES]", 'app.use("/api/a", a);');
|
|
137
|
+
const content = readFileSync(filePath, "utf-8");
|
|
138
|
+
expect(content).toContain('import { a } from "./a.js";');
|
|
139
|
+
expect(content).toContain('app.use("/api/a", a);');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
describe("getManualSteps", () => {
|
|
143
|
+
it("returns accumulated steps and clears the list", () => {
|
|
144
|
+
// Clear any existing steps
|
|
145
|
+
getManualSteps();
|
|
146
|
+
const filePath = join(tmpdir(), "nonexistent-file.ts");
|
|
147
|
+
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => { });
|
|
148
|
+
insertAtMarker(filePath, "// [MARKER]", "code1");
|
|
149
|
+
insertAtMarker(filePath, "// [MARKER]", "code2");
|
|
150
|
+
const steps = getManualSteps();
|
|
151
|
+
expect(steps.length).toBe(2);
|
|
152
|
+
// After retrieval, should be empty
|
|
153
|
+
const stepsAgain = getManualSteps();
|
|
154
|
+
expect(stepsAgain.length).toBe(0);
|
|
155
|
+
consoleSpy.mockRestore();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
//# sourceMappingURL=sail-installer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sail-installer.test.js","sourceRoot":"","sources":["../../src/__tests__/sail-installer.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create project logic — shared between create-keel binary and `keel create` command.
|
|
3
|
+
*
|
|
4
|
+
* Supports non-interactive mode:
|
|
5
|
+
* keel create my-app --yes # all defaults
|
|
6
|
+
* keel create my-app --yes --db=docker # specify database
|
|
7
|
+
* keel create my-app --yes --sails=stripe # with sails
|
|
8
|
+
* keel create my-app --yes --resend-key=re_xx --email-from=noreply@x.com
|
|
9
|
+
*/
|
|
10
|
+
export declare function main(args?: string[]): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=create-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-runner.d.ts","sourceRoot":"","sources":["../src/create-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAwD7D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create project logic — shared between create-keel binary and `keel create` command.
|
|
3
|
+
*
|
|
4
|
+
* Supports non-interactive mode:
|
|
5
|
+
* keel create my-app --yes # all defaults
|
|
6
|
+
* keel create my-app --yes --db=docker # specify database
|
|
7
|
+
* keel create my-app --yes --sails=stripe # with sails
|
|
8
|
+
* keel create my-app --yes --resend-key=re_xx --email-from=noreply@x.com
|
|
9
|
+
*/
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import { runPrompts, parseFlags } from "./prompts.js";
|
|
12
|
+
import { scaffold } from "./scaffold.js";
|
|
13
|
+
import { installSails } from "./sail-installer.js";
|
|
14
|
+
export async function main(args = []) {
|
|
15
|
+
const { projectName, flags } = parseFlags(args);
|
|
16
|
+
// Only show banner in interactive mode
|
|
17
|
+
if (!flags.yes) {
|
|
18
|
+
console.log();
|
|
19
|
+
console.log(chalk.blue(" ██╗ ██╗███████╗███████╗██╗ "));
|
|
20
|
+
console.log(chalk.blue(" ██║ ██╔╝██╔════╝██╔════╝██║ "));
|
|
21
|
+
console.log(chalk.blue(" █████╔╝ █████╗ █████╗ ██║ "));
|
|
22
|
+
console.log(chalk.blue(" ██╔═██╗ ██╔══╝ ██╔══╝ ██║ "));
|
|
23
|
+
console.log(chalk.blue(" ██║ ██╗███████╗███████╗███████╗"));
|
|
24
|
+
console.log(chalk.blue(" ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝"));
|
|
25
|
+
console.log();
|
|
26
|
+
console.log(chalk.gray(" a codai project"));
|
|
27
|
+
console.log();
|
|
28
|
+
}
|
|
29
|
+
let config;
|
|
30
|
+
try {
|
|
31
|
+
config = await runPrompts(projectName, flags);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
console.log(chalk.yellow("\n Cancelled.\n"));
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
console.log();
|
|
38
|
+
const success = await scaffold(config);
|
|
39
|
+
if (!success) {
|
|
40
|
+
console.log(chalk.red("\n Scaffolding failed. See errors above.\n"));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
// Install selected sails
|
|
44
|
+
if (config.sails.length > 0) {
|
|
45
|
+
console.log();
|
|
46
|
+
console.log(chalk.bold(" Installing sails..."));
|
|
47
|
+
await installSails(config);
|
|
48
|
+
}
|
|
49
|
+
// Done
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(chalk.green.bold(" ✔ Project created!"));
|
|
52
|
+
console.log();
|
|
53
|
+
console.log(chalk.bold(" Quick start:"));
|
|
54
|
+
console.log(chalk.cyan(` cd ${config.projectName}`));
|
|
55
|
+
console.log(chalk.cyan(" keel dev"));
|
|
56
|
+
console.log();
|
|
57
|
+
if (!config.resendApiKey) {
|
|
58
|
+
console.log(chalk.gray(" Tip: Set RESEND_API_KEY in .env for email sending."));
|
|
59
|
+
console.log();
|
|
60
|
+
}
|
|
61
|
+
process.exit(0);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=create-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-runner.js","sourceRoot":"","sources":["../src/create-runner.ts"],"names":[],"mappings":"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"}
|
package/dist/create.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
|
package/dist/create.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* create-keel CLI entry point (a codai project)
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx create-keel my-app
|
|
7
|
+
* npx create-keel # prompts for project name
|
|
8
|
+
*/
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import { main } from "./create-runner.js";
|
|
11
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
12
|
+
console.error(chalk.red("Unexpected error:"), err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
|
15
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/manage.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* keel CLI — Project management & sail tool (a codai project)
|
|
4
|
+
*
|
|
5
|
+
* Used from inside a keel project to manage sails, generate code,
|
|
6
|
+
* run database operations, and perform health checks.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx @codaijs/keel sail add <name> — install a sail into the current project
|
|
10
|
+
* npx @codaijs/keel sail remove <name> — remove a sail from the current project
|
|
11
|
+
* npx @codaijs/keel list — list available sails with status
|
|
12
|
+
* npx @codaijs/keel info <name> — show sail details
|
|
13
|
+
* npx @codaijs/keel doctor — run project health checks
|
|
14
|
+
* npx @codaijs/keel generate route <name> — scaffold a new API route
|
|
15
|
+
* npx @codaijs/keel generate page <name> — scaffold a new React page
|
|
16
|
+
* npx @codaijs/keel generate email <name> — scaffold a new email template
|
|
17
|
+
* npx @codaijs/keel db:reset — drop and recreate database schema
|
|
18
|
+
* npx @codaijs/keel db:studio — open Drizzle Studio
|
|
19
|
+
* npx @codaijs/keel db:seed — run database seed file
|
|
20
|
+
* npx @codaijs/keel env — check environment variables
|
|
21
|
+
* npx @codaijs/keel upgrade — upgrade keel CLI to latest version
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=manage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manage.d.ts","sourceRoot":"","sources":["../src/manage.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;GAoBG"}
|