From 9ac62387f22dcc9380c0b8f0fb9b2872f878a234 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 6 Jan 2025 17:10:40 +0900 Subject: [PATCH 1/4] feat(functions): auto add deno.jsonc and .npmrc to new functions --- internal/functions/new/new.go | 45 +++++++++++++++------ internal/functions/new/new_test.go | 10 +++++ internal/functions/new/templates/.npmrc | 3 ++ internal/functions/new/templates/deno.jsonc | 6 +++ 4 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 internal/functions/new/templates/.npmrc create mode 100644 internal/functions/new/templates/deno.jsonc diff --git a/internal/functions/new/new.go b/internal/functions/new/new.go index 3656e9b5f..fcab5a292 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -15,8 +15,13 @@ import ( var ( //go:embed templates/index.ts - indexEmbed string - indexTemplate = template.Must(template.New("indexl").Parse(indexEmbed)) + indexEmbed string + //go:embed templates/deno.jsonc + denoEmbed string + //go:embed templates/.npmrc + npmrcEmbed string + + indexTemplate = template.Must(template.New("index").Parse(indexEmbed)) ) type indexConfig struct { @@ -38,25 +43,41 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { if err := utils.MkdirIfNotExistFS(fsys, funcDir); err != nil { return err } - path := filepath.Join(funcDir, "index.ts") - f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) - if err != nil { - return errors.Errorf("failed to create function entrypoint: %w", err) - } - defer f.Close() - // Templatize index.ts by config.toml if available + + // Load config if available if err := utils.LoadConfigFS(fsys); err != nil { utils.CmdSuggestion = "" } - config := indexConfig{ + + if err := createTemplateFile(fsys, filepath.Join(funcDir, "index.ts"), indexTemplate, indexConfig{ URL: utils.GetApiUrl("/functions/v1/" + slug), Token: utils.Config.Auth.AnonKey, + }); err != nil { + return errors.Errorf("failed to create function entrypoint: %w", err) + } + + if err := afero.WriteFile(fsys, filepath.Join(funcDir, "deno.jsonc"), []byte(denoEmbed), 0644); err != nil { + return errors.Errorf("failed to create deno.jsonc config: %w", err) } - if err := indexTemplate.Option("missingkey=error").Execute(f, config); err != nil { - return errors.Errorf("failed to initialise function entrypoint: %w", err) + + if err := afero.WriteFile(fsys, filepath.Join(funcDir, ".npmrc"), []byte(npmrcEmbed), 0644); err != nil { + return errors.Errorf("failed to create .npmrc config: %w", err) } } fmt.Println("Created new Function at " + utils.Bold(funcDir)) return nil } + +func createTemplateFile(fsys afero.Fs, path string, tmpl *template.Template, data interface{}) error { + f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644) + if err != nil { + return err + } + defer f.Close() + + if data != nil { + return tmpl.Option("missingkey=error").Execute(f, data) + } + return tmpl.Execute(f, nil) +} diff --git a/internal/functions/new/new_test.go b/internal/functions/new/new_test.go index d5e9c2fc8..56a24f705 100644 --- a/internal/functions/new/new_test.go +++ b/internal/functions/new/new_test.go @@ -24,6 +24,16 @@ func TestNewCommand(t *testing.T) { assert.Contains(t, string(content), "curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/test-func'", ) + + // Verify deno.jsonc exists + denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.jsonc") + _, err = afero.ReadFile(fsys, denoPath) + assert.NoError(t, err, "deno.jsonc should be created") + + // Verify .npmrc exists + npmrcPath := filepath.Join(utils.FunctionsDir, "test-func", ".npmrc") + _, err = afero.ReadFile(fsys, npmrcPath) + assert.NoError(t, err, ".npmrc should be created") }) t.Run("throws error on malformed slug", func(t *testing.T) { diff --git a/internal/functions/new/templates/.npmrc b/internal/functions/new/templates/.npmrc new file mode 100644 index 000000000..e0bf63b94 --- /dev/null +++ b/internal/functions/new/templates/.npmrc @@ -0,0 +1,3 @@ +# Configuration for private npm package dependencies +# For more information on using private registries with Edge Functions, see: +# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries \ No newline at end of file diff --git a/internal/functions/new/templates/deno.jsonc b/internal/functions/new/templates/deno.jsonc new file mode 100644 index 000000000..97275ba5e --- /dev/null +++ b/internal/functions/new/templates/deno.jsonc @@ -0,0 +1,6 @@ +{ + "imports": { + // Add your dependencies here + // See: https://supabase.com/docs/guides/functions/import-maps#using-denojson-recommended + } +} From 6a7dd19c4c5ac356d2d20b7d2b8a85217e287ea7 Mon Sep 17 00:00:00 2001 From: avallete Date: Mon, 6 Jan 2025 17:30:30 +0900 Subject: [PATCH 2/4] feat(deploy): add warning for functions imports structure --- internal/functions/deploy/deploy.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go index 529b78976..5ee2ae845 100644 --- a/internal/functions/deploy/deploy.go +++ b/internal/functions/deploy/deploy.go @@ -71,6 +71,8 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool, // Although some functions do not require import map, it's more convenient to setup // vscode deno extension with a single import map for all functions. fallbackExists := true + functionsUsingDeprecatedGlobalFallback := []string{} + functionsUsingDeprecatedImportMap := []string{} if _, err := fsys.Stat(utils.FallbackImportMapPath); errors.Is(err, os.ErrNotExist) { fallbackExists = false } else if err != nil { @@ -94,12 +96,17 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool, } else if len(function.ImportMap) == 0 { denoJsonPath := filepath.Join(functionDir, "deno.json") denoJsoncPath := filepath.Join(functionDir, "deno.jsonc") + importMapPath := filepath.Join(functionDir, "import_map.json") if _, err := fsys.Stat(denoJsonPath); err == nil { function.ImportMap = denoJsonPath } else if _, err := fsys.Stat(denoJsoncPath); err == nil { function.ImportMap = denoJsoncPath + } else if _, err := fsys.Stat(importMapPath); err == nil { + function.ImportMap = importMapPath + functionsUsingDeprecatedImportMap = append(functionsUsingDeprecatedImportMap, name) } else if fallbackExists { function.ImportMap = utils.FallbackImportMapPath + functionsUsingDeprecatedGlobalFallback = append(functionsUsingDeprecatedGlobalFallback, name) } } if noVerifyJWT != nil { @@ -107,5 +114,12 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool, } functionConfig[name] = function } + if len(functionsUsingDeprecatedImportMap) > 0 { + fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "Functions using deprecated import_map.json (please migrate to deno.jsonc):", utils.Aqua(strings.Join(functionsUsingDeprecatedImportMap, ", "))) + } + if len(functionsUsingDeprecatedGlobalFallback) > 0 { + fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "Functions using fallback import map:", utils.Aqua(strings.Join(functionsUsingDeprecatedGlobalFallback, ", "))) + fmt.Fprintln(os.Stderr, "Please use recommended per function dependency declaration ", utils.Aqua("https://supabase.com/docs/guides/functions/import-maps")) + } return functionConfig, nil } From 81141d1dc5a66a72d41386126712529154b3548b Mon Sep 17 00:00:00 2001 From: Andrew Valleteau Date: Wed, 8 Jan 2025 16:55:55 +0900 Subject: [PATCH 3/4] Update internal/functions/new/templates/.npmrc Co-authored-by: Han Qiao --- internal/functions/new/templates/.npmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/functions/new/templates/.npmrc b/internal/functions/new/templates/.npmrc index e0bf63b94..48c638863 100644 --- a/internal/functions/new/templates/.npmrc +++ b/internal/functions/new/templates/.npmrc @@ -1,3 +1,3 @@ # Configuration for private npm package dependencies # For more information on using private registries with Edge Functions, see: -# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries \ No newline at end of file +# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries From f10838c7df4bfdfeb7689d6f5374884622eb4ad6 Mon Sep 17 00:00:00 2001 From: avallete Date: Wed, 8 Jan 2025 17:03:42 +0900 Subject: [PATCH 4/4] fix: function prototype --- internal/functions/new/new.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/internal/functions/new/new.go b/internal/functions/new/new.go index fcab5a292..f787ce90c 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -75,9 +75,5 @@ func createTemplateFile(fsys afero.Fs, path string, tmpl *template.Template, dat return err } defer f.Close() - - if data != nil { - return tmpl.Option("missingkey=error").Execute(f, data) - } - return tmpl.Execute(f, nil) + return tmpl.Option("missingkey=error").Execute(f, data) }