@t1mmen/srtd 0.2.1

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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/__tests__/vitest.setup.d.ts +2 -0
  4. package/dist/__tests__/vitest.setup.js +72 -0
  5. package/dist/__tests__/vitest.setup.js.map +1 -0
  6. package/dist/__tests__/watch.test.d.ts +1 -0
  7. package/dist/__tests__/watch.test.js +24 -0
  8. package/dist/__tests__/watch.test.js.map +1 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +7 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands/_app.d.ts +3 -0
  13. package/dist/commands/_app.js +7 -0
  14. package/dist/commands/_app.js.map +1 -0
  15. package/dist/commands/apply.d.ts +1 -0
  16. package/dist/commands/apply.js +20 -0
  17. package/dist/commands/apply.js.map +1 -0
  18. package/dist/commands/build.d.ts +1 -0
  19. package/dist/commands/build.js +15 -0
  20. package/dist/commands/build.js.map +1 -0
  21. package/dist/commands/help.d.ts +1 -0
  22. package/dist/commands/help.js +2 -0
  23. package/dist/commands/help.js.map +1 -0
  24. package/dist/commands/index.d.ts +2 -0
  25. package/dist/commands/index.js +37 -0
  26. package/dist/commands/index.js.map +1 -0
  27. package/dist/commands/init.d.ts +1 -0
  28. package/dist/commands/init.js +80 -0
  29. package/dist/commands/init.js.map +1 -0
  30. package/dist/commands/register.d.ts +8 -0
  31. package/dist/commands/register.js +82 -0
  32. package/dist/commands/register.js.map +1 -0
  33. package/dist/commands/watch.d.ts +2 -0
  34. package/dist/commands/watch.js +127 -0
  35. package/dist/commands/watch.js.map +1 -0
  36. package/dist/components/Branding.d.ts +6 -0
  37. package/dist/components/Branding.js +28 -0
  38. package/dist/components/Branding.js.map +1 -0
  39. package/dist/components/TimeSince.d.ts +4 -0
  40. package/dist/components/TimeSince.js +29 -0
  41. package/dist/components/TimeSince.js.map +1 -0
  42. package/dist/constants.d.ts +1 -0
  43. package/dist/constants.js +2 -0
  44. package/dist/constants.js.map +1 -0
  45. package/dist/hooks/useTemplateState.d.ts +6 -0
  46. package/dist/hooks/useTemplateState.js +28 -0
  47. package/dist/hooks/useTemplateState.js.map +1 -0
  48. package/dist/lib/templateManager.d.ts +32 -0
  49. package/dist/lib/templateManager.js +237 -0
  50. package/dist/lib/templateManager.js.map +1 -0
  51. package/dist/lib/templateManager.test.d.ts +1 -0
  52. package/dist/lib/templateManager.test.js +289 -0
  53. package/dist/lib/templateManager.test.js.map +1 -0
  54. package/dist/types.d.ts +44 -0
  55. package/dist/types.js +2 -0
  56. package/dist/types.js.map +1 -0
  57. package/dist/utils/applyMigration.d.ts +2 -0
  58. package/dist/utils/applyMigration.js +29 -0
  59. package/dist/utils/applyMigration.js.map +1 -0
  60. package/dist/utils/applyMigrations.test.d.ts +1 -0
  61. package/dist/utils/applyMigrations.test.js +112 -0
  62. package/dist/utils/applyMigrations.test.js.map +1 -0
  63. package/dist/utils/calculateMD5.d.ts +1 -0
  64. package/dist/utils/calculateMD5.js +5 -0
  65. package/dist/utils/calculateMD5.js.map +1 -0
  66. package/dist/utils/config.d.ts +3 -0
  67. package/dist/utils/config.js +78 -0
  68. package/dist/utils/config.js.map +1 -0
  69. package/dist/utils/config.test.d.ts +1 -0
  70. package/dist/utils/config.test.js +61 -0
  71. package/dist/utils/config.test.js.map +1 -0
  72. package/dist/utils/createEmptyBuildLog.d.ts +1 -0
  73. package/dist/utils/createEmptyBuildLog.js +10 -0
  74. package/dist/utils/createEmptyBuildLog.js.map +1 -0
  75. package/dist/utils/databaseConnection.d.ts +3 -0
  76. package/dist/utils/databaseConnection.js +45 -0
  77. package/dist/utils/databaseConnection.js.map +1 -0
  78. package/dist/utils/databaseConnection.test.d.ts +1 -0
  79. package/dist/utils/databaseConnection.test.js +45 -0
  80. package/dist/utils/databaseConnection.test.js.map +1 -0
  81. package/dist/utils/ensureDirectories.d.ts +4 -0
  82. package/dist/utils/ensureDirectories.js +23 -0
  83. package/dist/utils/ensureDirectories.js.map +1 -0
  84. package/dist/utils/fileExists.d.ts +1 -0
  85. package/dist/utils/fileExists.js +11 -0
  86. package/dist/utils/fileExists.js.map +1 -0
  87. package/dist/utils/getNextTimestamp.d.ts +2 -0
  88. package/dist/utils/getNextTimestamp.js +12 -0
  89. package/dist/utils/getNextTimestamp.js.map +1 -0
  90. package/dist/utils/isWipTemplate.d.ts +1 -0
  91. package/dist/utils/isWipTemplate.js +6 -0
  92. package/dist/utils/isWipTemplate.js.map +1 -0
  93. package/dist/utils/loadBuildLog.d.ts +2 -0
  94. package/dist/utils/loadBuildLog.js +21 -0
  95. package/dist/utils/loadBuildLog.js.map +1 -0
  96. package/dist/utils/loadBuildLog.test.d.ts +1 -0
  97. package/dist/utils/loadBuildLog.test.js +62 -0
  98. package/dist/utils/loadBuildLog.test.js.map +1 -0
  99. package/dist/utils/logger.d.ts +8 -0
  100. package/dist/utils/logger.js +11 -0
  101. package/dist/utils/logger.js.map +1 -0
  102. package/dist/utils/registerTemplate.d.ts +1 -0
  103. package/dist/utils/registerTemplate.js +44 -0
  104. package/dist/utils/registerTemplate.js.map +1 -0
  105. package/dist/utils/safeCreate.d.ts +1 -0
  106. package/dist/utils/safeCreate.js +10 -0
  107. package/dist/utils/safeCreate.js.map +1 -0
  108. package/dist/utils/saveBuildLog.d.ts +2 -0
  109. package/dist/utils/saveBuildLog.js +9 -0
  110. package/dist/utils/saveBuildLog.js.map +1 -0
  111. package/package.json +91 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Timm Stokke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # `srtd` 🪄 Supabase Repeatable Template Definitions
2
+
3
+ Live-reloading SQL templates for [Supabase](https://supabase.com) projects. DX supercharged! 🚀
4
+
5
+
6
+ `srtd` enhances the [Supabase](https://supabase.com) development workflow by adding live-reloading SQL templates, and a single-source-of-truth template migrations system for your database functions, RLS policies, etc. Drastically simplify code reviews 💪
7
+
8
+ Built specifically for projects using the standard [Supabase](https://supabase.com) stack (but probably works alright for other Postgres-based projects, too).
9
+
10
+ ## Why This Exists 🤔
11
+
12
+ While building [Timely](https://www.timely.com)'s next-generation [Memory Engine](https://www.timely.com/memory-app) on [Supabase](https://supabase.com), we found ourselves facing two major annoyances:
13
+
14
+ 1. Code reviews were painful - function changes showed up as complete rewrites rather than helpful diffs
15
+ 2. Designing and iterating on database changes locally meant constant friction, like the dance around copy-pasting into SQL console
16
+
17
+ After over a year of looking-but-not-finding a better way, I paired up with [Claude](https://claude.ai) to eliminate these annoyances. Say hello to `srtd`.
18
+
19
+ ## Key Features ✨
20
+
21
+ - **Live Reload**: Changes to your SQL templates instantly update your local database
22
+ - **Single Source of Truth**: Templates are the source of all (non-mutable) database objects, making code reviews a breeze
23
+ - **Clean Migrations**: Generate standard [Supabase](https://supabase.com) migrations when you're ready to deploy
24
+ - **Developer Friendly**: Interactive CLI with visual feedback for all operations
25
+
26
+ ## Requirements
27
+
28
+ - Node.js v20.x or higher
29
+ - [Supabase](https://supabase.com) CLI installed and project initialized (with `/supabase` directory)
30
+ - Local Postgres instance running (typically via `supabase start`)
31
+
32
+ ## Quick Start 🚀
33
+
34
+ First, install `srtd` globally or in your project:
35
+
36
+ ```bash
37
+ npm install -g srtd # Global installation
38
+ # or
39
+ npm install --save-dev srtd # Project installation
40
+ ```
41
+
42
+ Then set up in your [Supabase](https://supabase.com) project:
43
+
44
+ ```bash
45
+ cd your-supabase-project
46
+ srtd init
47
+ ```
48
+
49
+ Create a template (e.g., `supabase/migrations-templates/my_function.sql`):
50
+
51
+ ```sql
52
+ CREATE OR REPLACE FUNCTION my_function()
53
+ RETURNS void AS $$
54
+ BEGIN
55
+ -- Your function logic here
56
+ END;
57
+ $$ LANGUAGE plpgsql;
58
+ ```
59
+
60
+ Start development mode:
61
+
62
+ ```bash
63
+ srtd watch # Changes auto-apply to local database
64
+ ```
65
+
66
+ When ready to deploy:
67
+
68
+ ```bash
69
+ srtd build # Creates timestamped migration file
70
+ supabase migrate up # Apply using Supabase CLI
71
+ ```
72
+
73
+ ## Commands 🎮
74
+
75
+ Running `srtd` without arguments opens an interactive menu:
76
+
77
+ ```
78
+ ❯ 🏗️ build - Build Supabase migrations from templates
79
+ ▶️ apply - Apply migration templates directly to database
80
+ ✍️ register - Register templates as already built
81
+ 👀 watch - Watch templates for changes, apply directly to database
82
+ ```
83
+
84
+ Or use these commands directly:
85
+
86
+ - 🏗️ `build` - Generate [Supabase](https://supabase.com) migrations from templates
87
+ - ▶️ `apply` - Apply templates directly to local database
88
+ - ✍️ `register [file.sql]` - Mark templates as already built (interactive UI if no file specified)
89
+ - 👀 `watch` - Watch templates and apply changes instantly
90
+
91
+ ## Perfect For 🎯
92
+
93
+ Ideal for [Supabase](https://supabase.com) database objects that need full redefinition:
94
+
95
+ ✅ Functions and stored procedures:
96
+ ```sql
97
+ CREATE OR REPLACE FUNCTION search_products(query text, category_id uuid DEFAULT NULL)
98
+ RETURNS SETOF products AS $$
99
+ BEGIN
100
+ RETURN QUERY
101
+ SELECT p.* FROM products p
102
+ LEFT JOIN product_categories pc ON pc.product_id = p.id
103
+ WHERE to_tsvector('english',
104
+ p.name || ' ' ||
105
+ p.description || ' ' ||
106
+ p.tags || ' ' ||
107
+ COALESCE((
108
+ SELECT string_agg(c.name, ' ')
109
+ FROM categories c
110
+ WHERE c.id = ANY(p.category_ids)
111
+ ), '')
112
+ ) @@ plainto_tsquery('english', query)
113
+ AND (category_id IS NULL OR pc.category_id = category_id);
114
+ END;
115
+ $$ LANGUAGE plpgsql;
116
+ ```
117
+
118
+ ✅ Row-Level Security (RLS) policies:
119
+ ```sql
120
+ CREATE POLICY "users can view own data"
121
+ ON profiles FOR SELECT
122
+ USING (auth.uid() = user_id);
123
+ ```
124
+
125
+ ✅ Roles and permissions:
126
+ ```sql
127
+ CREATE ROLE authenticated;
128
+ GRANT USAGE ON SCHEMA public TO authenticated;
129
+ GRANT SELECT ON ALL TABLES IN SCHEMA public TO authenticated;
130
+ ```
131
+
132
+ **Not recommended for:**
133
+
134
+ * ❌ Table structures
135
+ * ❌ Indexes
136
+ * ❌ Data modifications
137
+ * ❌ Anything that is not fully re-definable, really.
138
+
139
+ In these cases, use regular [Supabase](https://supabase.com) migrations.
140
+
141
+ ## The Power of Templates 💪
142
+
143
+ Here's why templates make your life easier. Consider a PR that adds priority to our notification dispatch function.
144
+
145
+ With templates, the change is clear and reviewable:
146
+
147
+ ```diff
148
+ CREATE OR REPLACE FUNCTION dispatch_notification(
149
+ user_id uuid,
150
+ type text,
151
+ payload jsonb
152
+ ) RETURNS uuid AS $$
153
+ DECLARE
154
+ notification_id uuid;
155
+ user_settings jsonb;
156
+ BEGIN
157
+ -- Get user notification settings
158
+ SELECT settings INTO user_settings
159
+ FROM user_preferences
160
+ WHERE id = user_id;
161
+
162
+ -- Create notification record
163
+ + -- Include priority based on notification type
164
+ INSERT INTO notifications (
165
+ id,
166
+ user_id,
167
+ type,
168
+ payload,
169
+ + priority,
170
+ created_at
171
+ ) VALUES (
172
+ gen_random_uuid(),
173
+ dispatch_notification.user_id,
174
+ type,
175
+ payload,
176
+ + COALESCE((SELECT priority FROM notification_types WHERE name = type), 'normal'),
177
+ CURRENT_TIMESTAMP
178
+ )
179
+ RETURNING id INTO notification_id;
180
+ ```
181
+
182
+ Without templates, the same change appears as a complete new file in your PR.
183
+
184
+ ## Configuration 📝
185
+
186
+ During initialization, `srtd` creates a `srtd.config.json`:
187
+
188
+ ```json
189
+ {
190
+ "wipIndicator": ".wip",
191
+ "filter": "**/*.sql",
192
+ "banner": "You very likely **DO NOT** want to manually edit this generated file.",
193
+ "footer": "",
194
+ "wrapInTransaction": true,
195
+ "templateDir": "supabase/migrations-templates",
196
+ "migrationDir": "supabase/migrations",
197
+ "buildLog": "supabase/migrations-templates/.buildlog.json",
198
+ "localBuildLog": "supabase/migrations-templates/.buildlog.local.json",
199
+ "pgConnection": "postgresql://postgres:postgres@localhost:54322/postgres"
200
+ }
201
+ ```
202
+
203
+ ## Other Features 🔧
204
+
205
+ ### Work in Progress Templates
206
+
207
+ Add `.wip.sql` extension to templates under development to prevent accidental migration generation:
208
+
209
+ ```bash
210
+ my_function.wip.sql # Won't generate migrations during build
211
+ ```
212
+
213
+ ### Template State Management
214
+
215
+ `srtd` maintains two logs:
216
+
217
+ - `.buildlog.json` - Tracks which templates have been built into migrations (commit this)
218
+ - `.buildlog.local.json` - Tracks local database state (add to .gitignore)
219
+
220
+ ### Register Existing Objects
221
+
222
+ Import existing database objects into the template system:
223
+
224
+ ```bash
225
+ srtd register my_function.sql # Won't generate new migration until changed
226
+ # or
227
+ srtd register # Opens interactive UI for selecting multiple templates
228
+ ```
229
+
230
+ ## Development 🛠️
231
+
232
+ This project uses TypeScript and modern Node.js features. To contribute:
233
+
234
+ 1. Set up the development environment:
235
+ ```bash
236
+ git clone https://github.com/stokke/srtd.git
237
+ cd srtd
238
+ npm install
239
+ ```
240
+
241
+ 2. Start development:
242
+ ```bash
243
+ npm run dev # Watches for changes
244
+ npm test # Runs tests
245
+ npm start # Builds, links, and runs CLI
246
+ ```
247
+
248
+ 3. Other useful commands:
249
+ ```bash
250
+ npm run typecheck # Type checking
251
+ npm run lint # Lint and fix
252
+ npm run test:coverage # Test coverage
253
+ ```
254
+
255
+ ## Contributing 🤝
256
+
257
+ This tool was built to solve specific problems in our [Supabase](https://supabase.com) development workflow. While it's considered feature-complete for our needs, we welcome improvements through pull requests, especially for:
258
+
259
+ - Bug fixes and reliability improvements
260
+ - Documentation improvements and examples
261
+ - Test coverage
262
+ - Performance optimizations
263
+
264
+ ### Contribution Guidelines
265
+
266
+ 1. Create a [changeset](https://github.com/changesets/changesets) (`npm run changeset`)
267
+ 2. Ensure tests pass (`npm test`)
268
+ 3. Follow existing code style
269
+ 4. Update documentation as needed
270
+
271
+ Note that new features may or may not be accepted depending on whether they align with the project's focused scope. However, improvements to existing functionality, documentation, and tests are always welcome!
272
+
273
+ ## License
274
+
275
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
276
+
277
+ Made with 🪄 by [Timm Stokke](https://timm.stokke.me) & [Claude Sonnet](https://claude.ai)
@@ -0,0 +1,2 @@
1
+ export declare const TEST_FN_PREFIX = "srtd_scoped_test_func_";
2
+ export declare const TEST_ROOT: string;
@@ -0,0 +1,72 @@
1
+ import fs from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { afterAll, beforeAll, vi } from 'vitest';
5
+ import { connect, disconnect } from '../utils/databaseConnection.js';
6
+ export const TEST_FN_PREFIX = 'srtd_scoped_test_func_';
7
+ export const TEST_ROOT = join(tmpdir(), `srtd-test-${Date.now()}`);
8
+ if (process.env.CI) {
9
+ let consoleLogMock;
10
+ beforeAll(() => {
11
+ consoleLogMock = vi.spyOn(console, 'log').mockImplementation(() => {
12
+ // Do nothing
13
+ });
14
+ });
15
+ afterAll(() => {
16
+ consoleLogMock.mockRestore();
17
+ });
18
+ }
19
+ beforeAll(async () => {
20
+ await fs.mkdir(TEST_ROOT, { recursive: true });
21
+ });
22
+ afterAll(async () => {
23
+ await fs.rm(TEST_ROOT, { recursive: true, force: true });
24
+ // Be extra sure to clean up any test functions from db
25
+ const client = await connect();
26
+ try {
27
+ await client.query('BEGIN');
28
+ await client.query(`
29
+ DO $$
30
+ DECLARE
31
+ r record;
32
+ BEGIN
33
+ FOR r IN
34
+ SELECT quote_ident(proname) AS func_name
35
+ FROM pg_proc
36
+ WHERE proname LIKE '${TEST_FN_PREFIX}%'
37
+ LOOP
38
+ EXECUTE 'DROP FUNCTION IF EXISTS ' || r.func_name;
39
+ END LOOP;
40
+ END;
41
+ $$
42
+ `);
43
+ await client.query('COMMIT');
44
+ }
45
+ catch (e) {
46
+ await client.query('ROLLBACK');
47
+ throw e;
48
+ }
49
+ finally {
50
+ client.release();
51
+ }
52
+ disconnect();
53
+ });
54
+ vi.mock('../utils/config', async (importOriginal) => {
55
+ const actual = (await importOriginal());
56
+ return {
57
+ ...actual,
58
+ getConfig: vi.fn().mockResolvedValue({
59
+ wipIndicator: '.wip',
60
+ filter: '**/*.sql',
61
+ templateDir: 'test-templates',
62
+ migrationDir: 'test-migrations',
63
+ buildLog: '.buildlog-test.json',
64
+ localBuildLog: '.buildlog-test.local.json',
65
+ pgConnection: process.env.POSTGRES_URL || 'postgresql://postgres:postgres@localhost:54322/postgres',
66
+ banner: 'Test banner',
67
+ footer: 'Test footer',
68
+ wrapInTransaction: true,
69
+ }),
70
+ };
71
+ });
72
+ //# sourceMappingURL=vitest.setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest.setup.js","sourceRoot":"","sources":["../../src/__tests__/vitest.setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAErE,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AACvD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAEnE,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;IACnB,IAAI,cAA2C,CAAC;IAEhD,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,kBAAkB,CAAC,GAAG,EAAE;YAChE,aAAa;QACf,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE;QACZ,cAAc,CAAC,WAAW,EAAE,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;IAClB,MAAM,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,uDAAuD;IACvD,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;gCAQS,cAAc;;;;;;KAMzC,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,CAAC,CAAC;IACV,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,UAAU,EAAE,CAAC;AACf,CAAC,CAAC,CAAC;AAEH,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE;IAChD,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,EAAE,CAAwC,CAAC;IAC/E,OAAO;QACL,GAAG,MAAM;QACT,SAAS,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;YACnC,YAAY,EAAE,MAAM;YACpB,MAAM,EAAE,UAAU;YAClB,WAAW,EAAE,gBAAgB;YAC7B,YAAY,EAAE,iBAAiB;YAC/B,QAAQ,EAAE,qBAAqB;YAC/B,aAAa,EAAE,2BAA2B;YAC1C,YAAY,EACV,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,yDAAyD;YACvF,MAAM,EAAE,aAAa;YACrB,MAAM,EAAE,aAAa;YACrB,iBAAiB,EAAE,IAAI;SACxB,CAAC;KACH,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { render } from 'ink-testing-library';
2
+ import React from 'react';
3
+ import { beforeEach, describe, expect, test, vi } from 'vitest';
4
+ import Watch from '../commands/watch.js';
5
+ vi.mock('ink', async (importOriginal) => {
6
+ const actual = (await importOriginal());
7
+ return {
8
+ ...actual,
9
+ useApp: () => ({ exit: vi.fn() }),
10
+ };
11
+ });
12
+ describe('Watch Command', () => {
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ });
16
+ test('renders initial state with no templates', async () => {
17
+ const { lastFrame } = render(React.createElement(Watch, null));
18
+ await new Promise(resolve => setTimeout(resolve, 100));
19
+ const output = lastFrame();
20
+ expect(output).toContain('Watch Mode');
21
+ expect(output).toContain('Watching for template changes');
22
+ });
23
+ });
24
+ //# sourceMappingURL=watch.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.test.js","sourceRoot":"","sources":["../../src/__tests__/watch.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAChE,OAAO,KAAK,MAAM,sBAAsB,CAAC;AAEzC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAC,cAAc,EAAC,EAAE;IACpC,MAAM,MAAM,GAAG,CAAC,MAAM,cAAc,EAAE,CAAyB,CAAC;IAChE,OAAO;QACL,GAAG,MAAM;QACT,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;KAClC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC,oBAAC,KAAK,OAAG,CAAC,CAAC;QACxC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env -S node --no-warnings
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env -S node --no-warnings
2
+ import Pastel from 'pastel';
3
+ const app = new Pastel({
4
+ importMeta: import.meta,
5
+ });
6
+ await app.run();
7
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":";AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC,IAAI;CACxB,CAAC,CAAC;AAEH,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AppProps } from 'pastel';
2
+ import React from 'react';
3
+ export default function App({ Component, commandProps }: AppProps): React.JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { Box } from 'ink';
2
+ import React from 'react';
3
+ export default function App({ Component, commandProps }) {
4
+ return (React.createElement(Box, { flexDirection: "column" },
5
+ React.createElement(Component, { ...commandProps })));
6
+ }
7
+ //# sourceMappingURL=_app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_app.js","sourceRoot":"","sources":["../../src/commands/_app.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY,EAAY;IAC/D,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,SAAS,OAAK,YAAY,GAAI,CAC3B,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export default function Apply(): null;
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import { TemplateManager } from '../lib/templateManager.js';
3
+ export default function Apply() {
4
+ React.useEffect(() => {
5
+ async function doApply() {
6
+ try {
7
+ const manager = await TemplateManager.create(process.cwd());
8
+ await manager.processTemplates({ apply: true });
9
+ process.exit(0);
10
+ }
11
+ catch (err) {
12
+ console.error('Error:', err instanceof Error ? err.message : String(err));
13
+ process.exit(1);
14
+ }
15
+ }
16
+ void doApply();
17
+ }, []);
18
+ return null;
19
+ }
20
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/commands/apply.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,CAAC,OAAO,UAAU,KAAK;IAC3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,KAAK,UAAU,OAAO;YACpB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC5D,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QACD,KAAK,OAAO,EAAE,CAAC;IACjB,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export default function Build(): null;
@@ -0,0 +1,15 @@
1
+ // commands/build.tsx
2
+ import React from 'react';
3
+ import { TemplateManager } from '../lib/templateManager.js';
4
+ export default function Build() {
5
+ React.useEffect(() => {
6
+ async function doBuild() {
7
+ const manager = await TemplateManager.create(process.cwd());
8
+ await manager.processTemplates({ generateFiles: true });
9
+ process.exit(0);
10
+ }
11
+ doBuild();
12
+ }, []);
13
+ return null;
14
+ }
15
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.tsx"],"names":[],"mappings":"AAAA,qBAAqB;AACrB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,CAAC,OAAO,UAAU,KAAK;IAC3B,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,KAAK,UAAU,OAAO;YACpB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAC5D,MAAM,OAAO,CAAC,gBAAgB,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export default function UI(): React.JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { Select } from '@inkjs/ui';
2
+ import { Box } from 'ink';
3
+ import React from 'react';
4
+ import Branding from '../components/Branding.js';
5
+ import Apply from './apply.js';
6
+ import Build from './build.js';
7
+ import Register from './register.js';
8
+ import Watch from './watch.js';
9
+ export default function UI() {
10
+ const [selectedCommand, setSelectedCommand] = React.useState(null);
11
+ // For now, we only demonstrate navigation to "register"
12
+ if (selectedCommand === 'register') {
13
+ return React.createElement(Register, { args: undefined });
14
+ }
15
+ if (selectedCommand === 'apply') {
16
+ return React.createElement(Apply, null);
17
+ }
18
+ if (selectedCommand === 'build') {
19
+ return React.createElement(Build, null);
20
+ }
21
+ if (selectedCommand === 'watch') {
22
+ return React.createElement(Watch, null);
23
+ }
24
+ const menuItems = [
25
+ { label: '🏗️ build - Build Supabase migrations from templates', value: 'build' },
26
+ { label: '▶️ apply - Apply migration templates directly to database', value: 'apply' },
27
+ { label: '✍️ register - Register templates as already built', value: 'register' },
28
+ {
29
+ label: '👀 watch - Watch templates for changes and apply directly to database',
30
+ value: 'watch',
31
+ },
32
+ ];
33
+ return (React.createElement(Box, { flexDirection: "column" },
34
+ React.createElement(Branding, null),
35
+ React.createElement(Select, { options: menuItems, onChange: value => setSelectedCommand(value) })));
36
+ }
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AACjD,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,CAAC,OAAO,UAAU,EAAE;IACxB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAElF,wDAAwD;IACxD,IAAI,eAAe,KAAK,UAAU,EAAE,CAAC;QACnC,OAAO,oBAAC,QAAQ,IAAC,IAAI,EAAE,SAAS,GAAI,CAAC;IACvC,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;QAChC,OAAO,oBAAC,KAAK,OAAG,CAAC;IACnB,CAAC;IAED,MAAM,SAAS,GAAG;QAChB,EAAE,KAAK,EAAE,uDAAuD,EAAE,KAAK,EAAE,OAAO,EAAE;QAClF,EAAE,KAAK,EAAE,4DAA4D,EAAE,KAAK,EAAE,OAAO,EAAE;QACvF,EAAE,KAAK,EAAE,oDAAoD,EAAE,KAAK,EAAE,UAAU,EAAE;QAClF;YACE,KAAK,EAAE,wEAAwE;YAC/E,KAAK,EAAE,OAAO;SACf;KACF,CAAC;IAEF,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ;QACzB,oBAAC,QAAQ,OAAG;QACZ,oBAAC,MAAM,IAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAI,CACxE,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ export default function Init(): null;
@@ -0,0 +1,80 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ import React from 'react';
5
+ import { CONFIG_FILE } from '../constants.js';
6
+ import { getConfig, saveConfig } from '../utils/config.js';
7
+ import { createEmptyBuildLog } from '../utils/createEmptyBuildLog.js';
8
+ import { ensureDirectories } from '../utils/ensureDirectories.js';
9
+ import { fileExists } from '../utils/fileExists.js';
10
+ import { logger } from '../utils/logger.js';
11
+ export default function Init() {
12
+ React.useEffect(() => {
13
+ async function doInit() {
14
+ console.log(`${chalk.green('\n✨ Initializing srtd\n')}`);
15
+ try {
16
+ const baseDir = process.cwd();
17
+ const config = await getConfig(baseDir);
18
+ const configPath = path.join(baseDir, CONFIG_FILE);
19
+ if (await fileExists(configPath)) {
20
+ logger.skip(`${CONFIG_FILE} already exists`);
21
+ }
22
+ else {
23
+ await saveConfig(baseDir, {});
24
+ logger.success(`Created ${CONFIG_FILE} with default configuration`);
25
+ }
26
+ const dirs = await ensureDirectories(baseDir);
27
+ if (dirs.templateDir) {
28
+ logger.success(`Created template directory ${config.templateDir}`);
29
+ }
30
+ else {
31
+ logger.skip(`Template directory ${config.templateDir} already exists`);
32
+ }
33
+ if (dirs.migrationDir) {
34
+ logger.success(`Created migration directory ${config.migrationDir}`);
35
+ }
36
+ else {
37
+ logger.skip(`Migration directory ${config.migrationDir} already exists`);
38
+ }
39
+ const buildLogCreated = await createEmptyBuildLog(path.join(baseDir, config.buildLog));
40
+ const localBuildLogCreated = await createEmptyBuildLog(path.join(baseDir, config.localBuildLog));
41
+ if (buildLogCreated) {
42
+ logger.success(`Created build log at ${config.buildLog}`);
43
+ }
44
+ else {
45
+ logger.skip(`Build log already exists at ${config.buildLog}`);
46
+ }
47
+ if (localBuildLogCreated) {
48
+ logger.success(`Created local build log at ${config.localBuildLog}`);
49
+ }
50
+ else {
51
+ logger.skip(`Local build log already exists at ${config.localBuildLog}`);
52
+ }
53
+ const gitignorePath = path.join(baseDir, '.gitignore');
54
+ const ignoreEntry = path.basename(config.localBuildLog);
55
+ let content = '';
56
+ try {
57
+ content = await fs.readFile(gitignorePath, 'utf-8');
58
+ }
59
+ catch {
60
+ // Ignore
61
+ }
62
+ if (!content.includes(ignoreEntry)) {
63
+ content = `${content.trim()}\n\n# srtd's local logs should not be committed, as they're per-environment specific\n${ignoreEntry}\n`;
64
+ await fs.writeFile(gitignorePath, content);
65
+ logger.success(`Added ${ignoreEntry} to .gitignore`);
66
+ }
67
+ else {
68
+ logger.skip(`.gitignore already contains ${ignoreEntry}`);
69
+ }
70
+ }
71
+ catch (error) {
72
+ logger.error(`Failed to initialize: ${JSON.stringify(error)}`);
73
+ process.exit(1);
74
+ }
75
+ }
76
+ doInit();
77
+ }, []);
78
+ return null;
79
+ }
80
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import zod from 'zod';
3
+ export declare const args: zod.ZodOptional<zod.ZodArray<zod.ZodString, "many">>;
4
+ type Props = {
5
+ args: zod.infer<typeof args>;
6
+ };
7
+ export default function Register({ args: templateArgs }: Props): React.JSX.Element;
8
+ export {};