go-duck-cli 1.2.2 → 1.2.3

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/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  <p align="center">
14
14
  <a href="https://badge.fury.io/js/go-duck-cli"><img src="https://badge.fury.io/js/go-duck-cli.svg" alt="npm version"></a>
15
15
  <a href="https://opensource.org/licenses/ISC"><img src="https://img.shields.io/badge/License-ISC-blue.svg" alt="License: ISC"></a>
16
+ ![Version](https://img.shields.io/badge/version-1.2.25-blue)
16
17
  </p>
17
18
 
18
19
  ---
@@ -106,6 +107,15 @@ Ensure your development environment meets the following requirements:
106
107
  * **Docker:** v20+
107
108
  * **Composability:** v2+
108
109
 
110
+ ## Quick‑Start
111
+
112
+ Follow these four steps to get a generated microservice running locally and in Kubernetes:
113
+
114
+ 1. **Create**: `go-duck create -o ./my-app -c config.yaml`
115
+ 2. **Enter**: `cd my-app`
116
+ 3. **Build & Push**: `./push.sh my-registry/my-app:1.0.0`
117
+ 4. **Deploy**: `kubectl apply -f devops/k8s/`
118
+
109
119
  ## 🚀 Scaffold & Run
110
120
 
111
121
  Follow these steps to create and run a new microservice with GO-DUCK:
@@ -116,6 +126,36 @@ go-duck create -o ./my-app -c config.yaml
116
126
 
117
127
  # 2. Enter the application directory
118
128
  cd my-app
129
+
130
+ # 3. Build, tag, and push Docker image (updates app.yaml)
131
+ ./push.sh my-registry/my-app:1.0.0
132
+
133
+ # 4. Deploy to Kubernetes
134
+ kubectl apply -f devops/k8s/
135
+
136
+ ### 🚢 Deploy to Kubernetes & Push Images
137
+
138
+ The generated project includes a **devops/k8s** directory with ready‑to‑apply Kubernetes manifests:
139
+
140
+ - `mongo.yaml` – StatefulSet & Service for MongoDB.
141
+ - `minio.yaml` – Deployment & Service for MinIO object storage.
142
+ - `app.yaml` – Deployment for the generated Go microservice, referencing a placeholder image name (`<app‑name>:latest`). Replace the image with the tag you push.
143
+
144
+ A helper script **push.sh** (located at the project root) automates the Docker build, tag, push, and then updates the `app.yaml` image field:
145
+
146
+ ```bash
147
+ ./push.sh my-registry/my-app:1.0.0
148
+ ```
149
+
150
+ After pushing, deploy everything with:
151
+
152
+ ```bash
153
+ kubectl apply -f devops/k8s/
154
+ ```
155
+
156
+ > [!NOTE]
157
+ > The K8s manifests use placeholder values (e.g., resource limits, storage class). Adjust them to match your cluster requirements before applying.
158
+
119
159
  ```
120
160
 
121
161
  ### 🏗️ Compiling Protobuf & gRPC Contracts
@@ -126,7 +126,8 @@ export const generateAIDocs = async (config, entities, outputDir, enums, openEnt
126
126
  agentInstructions += `### High-Velocity Commands:\n`;
127
127
  agentInstructions += `- **Build Project**: \`go build ./...\`\n`;
128
128
  agentInstructions += `- **Protobuf Compilation**: \`./generate.sh\` (or \`.\\generate.bat\` on Windows)\n`;
129
- agentInstructions += `- **Local Dependencies & Dev Boot**: \`docker-compose up -d && go run main.go\`\n\n`;
129
+ agentInstructions += `- **Local Dependencies & Dev Boot**: \`docker-compose up -d && go run main.go\`\n`;
130
+ agentInstructions += `- **Docker Build & Push**: \`./push.sh\` (Builds and pushes the Docker image to registry)\n\n`;
130
131
  agentInstructions += `### GDL Evolution & Schema Deletions:\n`;
131
132
  agentInstructions += `- **Snapshot Merging (Multi-File GDL)**: The generator implements stateful snapshot merging. Running \`import-gdl\` on a single GDL file will NOT wipe out other entities; previous snapshots are retrieved from the \`.go-duck/\` state folder and merged automatically.\n`;
132
133
  agentInstructions += `- **Altering/Dropping Fields**: To add, drop, or edit fields within an entity, update the fields inline in the GDL entity block. Running \`import-gdl\` generates targeted Goose SQL column-level migrations.\n`;
@@ -400,6 +400,502 @@ jobs:
400
400
  ]
401
401
  }, null, 4);
402
402
 
403
+ const pushScript = `#!/usr/bin/env bash
404
+ # Exit immediately if a command exits with a non-zero status
405
+ set -e
406
+
407
+ # --- CONFIGURATION ---
408
+ # Edit these variables to hardcode your values, or leave them to fallback to environment variables.
409
+ DOCKER_USER="\${DOCKER_USER:-your-dockerhub-username}"
410
+ IMAGE_NAME="\${IMAGE_NAME:-${appName}}"
411
+ VERSION="\${VERSION:-1.0.0}"
412
+ # ---------------------
413
+
414
+ # Build the full image tag
415
+ TAG="\${DOCKER_USER}/\${IMAGE_NAME}:\${VERSION}"
416
+
417
+ echo "========================================="
418
+ echo "Building Docker image: \$TAG"
419
+ echo "========================================="
420
+ docker build -f devops/Dockerfile -t "\$TAG" .
421
+
422
+ echo "========================================="
423
+ echo "Pushing Docker image: \$TAG"
424
+ echo "========================================="
425
+ docker push "\$TAG"
426
+
427
+ echo "========================================="
428
+ echo "Successfully built and published \$TAG"
429
+ echo "========================================="
430
+ `;
431
+
432
+ const k8sAppYaml = `apiVersion: apps/v1
433
+ kind: Deployment
434
+ metadata:
435
+ name: ${appName}
436
+ labels:
437
+ app: ${appName}
438
+ spec:
439
+ replicas: 1
440
+ selector:
441
+ matchLabels:
442
+ app: ${appName}
443
+ template:
444
+ metadata:
445
+ labels:
446
+ app: ${appName}
447
+ spec:
448
+ containers:
449
+ - name: ${appName}
450
+ image: ${appName}:latest
451
+ env:
452
+ - name: GO_PROFILE
453
+ value: prod
454
+ - name: GO_DUCK_SERVER_REST_PORT
455
+ value: "${appPort}"
456
+ - name: GO_DUCK_DATASOURCE_HOST
457
+ value: postgres
458
+ - name: GO_DUCK_DATASOURCE_USERNAME
459
+ value: "${config.datasource?.username || 'postgres'}"
460
+ - name: GO_DUCK_DATASOURCE_PASSWORD
461
+ value: "${config.datasource?.password || 'password'}"
462
+ - name: GO_DUCK_DATASOURCE_DATABASE
463
+ value: "${config.datasource?.database || 'go_duck_master'}"
464
+ - name: GO_DUCK_DATASOURCE_PORT
465
+ value: "5432"
466
+ - name: GO_DUCK_CACHE_REDIS_HOST
467
+ value: redis:6379
468
+ - name: GO_DUCK_MESSAGING_MQTT_BROKER
469
+ value: tcp://mosquitto:1883
470
+ - name: GO_DUCK_MESSAGING_NATS_URL
471
+ value: nats://nats:4222
472
+ - name: GO_DUCK_TELEMETRY_OTEL_ENDPOINT
473
+ value: otel-collector:4317
474
+ - name: GO_DUCK_ELASTICSEARCH_ADDRESSES
475
+ value: http://elasticsearch:9200
476
+ - name: GO_DUCK_SECURITY_KEYCLOAK_HOST
477
+ value: http://keycloak:8080
478
+ ports:
479
+ - name: http
480
+ containerPort: ${appPort}
481
+ - name: grpc
482
+ containerPort: 9000
483
+ ---
484
+ apiVersion: v1
485
+ kind: Service
486
+ metadata:
487
+ name: ${appName}
488
+ spec:
489
+ ports:
490
+ - name: http
491
+ port: ${appPort}
492
+ targetPort: http
493
+ - name: grpc
494
+ port: 9000
495
+ targetPort: grpc
496
+ selector:
497
+ app: ${appName}
498
+ `;
499
+
500
+ const k8sPostgresYaml = `apiVersion: v1
501
+ kind: PersistentVolumeClaim
502
+ metadata:
503
+ name: postgres-pvc
504
+ spec:
505
+ accessModes:
506
+ - ReadWriteOnce
507
+ resources:
508
+ requests:
509
+ storage: 1Gi
510
+ ---
511
+ apiVersion: apps/v1
512
+ kind: Deployment
513
+ metadata:
514
+ name: postgres
515
+ labels:
516
+ app: postgres
517
+ spec:
518
+ replicas: 1
519
+ selector:
520
+ matchLabels:
521
+ app: postgres
522
+ template:
523
+ metadata:
524
+ labels:
525
+ app: postgres
526
+ spec:
527
+ containers:
528
+ - name: postgres
529
+ image: postgres:15.6-alpine
530
+ env:
531
+ - name: POSTGRES_USER
532
+ value: "${config.datasource?.username || 'postgres'}"
533
+ - name: POSTGRES_PASSWORD
534
+ value: "${config.datasource?.password || 'password'}"
535
+ - name: POSTGRES_DB
536
+ value: "${config.datasource?.database || 'go_duck_master'}"
537
+ ports:
538
+ - containerPort: 5432
539
+ volumeMounts:
540
+ - name: postgres-storage
541
+ mountPath: /var/lib/postgresql/data
542
+ volumes:
543
+ - name: postgres-storage
544
+ persistentVolumeClaim:
545
+ claimName: postgres-pvc
546
+ ---
547
+ apiVersion: v1
548
+ kind: Service
549
+ metadata:
550
+ name: postgres
551
+ spec:
552
+ ports:
553
+ - port: 5432
554
+ selector:
555
+ app: postgres
556
+ `;
557
+
558
+ const k8sRedisYaml = `apiVersion: apps/v1
559
+ kind: Deployment
560
+ metadata:
561
+ name: redis
562
+ labels:
563
+ app: redis
564
+ spec:
565
+ replicas: 1
566
+ selector:
567
+ matchLabels:
568
+ app: redis
569
+ template:
570
+ metadata:
571
+ labels:
572
+ app: redis
573
+ spec:
574
+ containers:
575
+ - name: redis
576
+ image: redis:7.2.4-alpine
577
+ ports:
578
+ - containerPort: 6379
579
+ ---
580
+ apiVersion: v1
581
+ kind: Service
582
+ metadata:
583
+ name: redis
584
+ spec:
585
+ ports:
586
+ - port: 6379
587
+ selector:
588
+ app: redis
589
+ `;
590
+
591
+ const k8sNatsYaml = `apiVersion: apps/v1
592
+ kind: Deployment
593
+ metadata:
594
+ name: nats
595
+ labels:
596
+ app: nats
597
+ spec:
598
+ replicas: 1
599
+ selector:
600
+ matchLabels:
601
+ app: nats
602
+ template:
603
+ metadata:
604
+ labels:
605
+ app: nats
606
+ spec:
607
+ containers:
608
+ - name: nats
609
+ image: nats:2.10.12-alpine
610
+ ports:
611
+ - containerPort: 4222
612
+ ---
613
+ apiVersion: v1
614
+ kind: Service
615
+ metadata:
616
+ name: nats
617
+ spec:
618
+ ports:
619
+ - port: 4222
620
+ selector:
621
+ app: nats
622
+ `;
623
+
624
+ const k8sMosquittoYaml = `apiVersion: v1
625
+ kind: ConfigMap
626
+ metadata:
627
+ name: mosquitto-config
628
+ data:
629
+ mosquitto.conf: |
630
+ listener 1883
631
+ listener 9001
632
+ protocol websockets
633
+ allow_anonymous true
634
+ ---
635
+ apiVersion: apps/v1
636
+ kind: Deployment
637
+ metadata:
638
+ name: mosquitto
639
+ labels:
640
+ app: mosquitto
641
+ spec:
642
+ replicas: 1
643
+ selector:
644
+ matchLabels:
645
+ app: mosquitto
646
+ template:
647
+ metadata:
648
+ labels:
649
+ app: mosquitto
650
+ spec:
651
+ containers:
652
+ - name: mosquitto
653
+ image: eclipse-mosquitto:2.0.18
654
+ ports:
655
+ - containerPort: 1883
656
+ - containerPort: 9001
657
+ volumeMounts:
658
+ - name: config-volume
659
+ mountPath: /mosquitto/config/mosquitto.conf
660
+ subPath: mosquitto.conf
661
+ volumes:
662
+ - name: config-volume
663
+ configMap:
664
+ name: mosquitto-config
665
+ ---
666
+ apiVersion: v1
667
+ kind: Service
668
+ metadata:
669
+ name: mosquitto
670
+ spec:
671
+ ports:
672
+ - name: mqtt
673
+ port: 1883
674
+ - name: ws
675
+ port: 9001
676
+ selector:
677
+ app: mosquitto
678
+ `;
679
+
680
+ const k8sElasticsearchYaml = `apiVersion: apps/v1
681
+ kind: Deployment
682
+ metadata:
683
+ name: elasticsearch
684
+ labels:
685
+ app: elasticsearch
686
+ spec:
687
+ replicas: 1
688
+ selector:
689
+ matchLabels:
690
+ app: elasticsearch
691
+ template:
692
+ metadata:
693
+ labels:
694
+ app: elasticsearch
695
+ spec:
696
+ containers:
697
+ - name: elasticsearch
698
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.12.2
699
+ env:
700
+ - name: discovery.type
701
+ value: single-node
702
+ - name: xpack.security.enabled
703
+ value: "false"
704
+ - name: ES_JAVA_OPTS
705
+ value: "-Xms512m -Xmx512m"
706
+ ports:
707
+ - containerPort: 9200
708
+ ---
709
+ apiVersion: v1
710
+ kind: Service
711
+ metadata:
712
+ name: elasticsearch
713
+ spec:
714
+ ports:
715
+ - port: 9200
716
+ selector:
717
+ app: elasticsearch
718
+ `;
719
+
720
+ const k8sJaegerYaml = `apiVersion: apps/v1
721
+ kind: Deployment
722
+ metadata:
723
+ name: jaeger
724
+ labels:
725
+ app: jaeger
726
+ spec:
727
+ replicas: 1
728
+ selector:
729
+ matchLabels:
730
+ app: jaeger
731
+ template:
732
+ metadata:
733
+ labels:
734
+ app: jaeger
735
+ spec:
736
+ containers:
737
+ - name: jaeger
738
+ image: jaegertracing/all-in-one:1.55
739
+ ports:
740
+ - containerPort: 16686
741
+ - containerPort: 4317
742
+ env:
743
+ - name: COLLECTOR_OTLP_ENABLED
744
+ value: "true"
745
+ ---
746
+ apiVersion: v1
747
+ kind: Service
748
+ metadata:
749
+ name: jaeger
750
+ spec:
751
+ ports:
752
+ - name: ui
753
+ port: 16686
754
+ - name: otlp-grpc
755
+ port: 4317
756
+ selector:
757
+ app: jaeger
758
+ `;
759
+
760
+ const k8sOtelCollectorYaml = `apiVersion: v1
761
+ kind: ConfigMap
762
+ metadata:
763
+ name: otel-collector-config
764
+ data:
765
+ otel-collector.yaml: |
766
+ receivers:
767
+ otlp:
768
+ protocols:
769
+ grpc:
770
+ http:
771
+ processors:
772
+ batch:
773
+ resourcedetection:
774
+ detectors: [env, system]
775
+ exporters:
776
+ logging:
777
+ loglevel: debug
778
+ otlp:
779
+ endpoint: "jaeger:4317"
780
+ tls:
781
+ insecure: true
782
+ service:
783
+ pipelines:
784
+ traces:
785
+ receivers: [otlp]
786
+ processors: [batch, resourcedetection]
787
+ exporters: [logging, otlp]
788
+ ---
789
+ apiVersion: apps/v1
790
+ kind: Deployment
791
+ metadata:
792
+ name: otel-collector
793
+ labels:
794
+ app: otel-collector
795
+ spec:
796
+ replicas: 1
797
+ selector:
798
+ matchLabels:
799
+ app: otel-collector
800
+ template:
801
+ metadata:
802
+ labels:
803
+ app: otel-collector
804
+ spec:
805
+ containers:
806
+ - name: otel-collector
807
+ image: otel/opentelemetry-collector-contrib:0.96.0
808
+ command:
809
+ - --config=/etc/otel-collector-config.yaml
810
+ ports:
811
+ - containerPort: 4317
812
+ - containerPort: 4318
813
+ volumeMounts:
814
+ - name: config-volume
815
+ mountPath: /etc/otel-collector-config.yaml
816
+ subPath: otel-collector.yaml
817
+ volumes:
818
+ - name: config-volume
819
+ configMap:
820
+ name: otel-collector-config
821
+ ---
822
+ apiVersion: v1
823
+ kind: Service
824
+ metadata:
825
+ name: otel-collector
826
+ spec:
827
+ ports:
828
+ - name: otlp-grpc
829
+ port: 4317
830
+ - name: otlp-http
831
+ port: 4318
832
+ selector:
833
+ app: otel-collector
834
+ `;
835
+
836
+ const k8sKeycloakYaml = `apiVersion: v1
837
+ kind: ConfigMap
838
+ metadata:
839
+ name: keycloak-realm-config
840
+ data:
841
+ realm.json: |
842
+ ${realmJson.split('\n').map(l => ' ' + l).join('\n')}
843
+ ---
844
+ apiVersion: apps/v1
845
+ kind: Deployment
846
+ metadata:
847
+ name: keycloak
848
+ labels:
849
+ app: keycloak
850
+ spec:
851
+ replicas: 1
852
+ selector:
853
+ matchLabels:
854
+ app: keycloak
855
+ template:
856
+ metadata:
857
+ labels:
858
+ app: keycloak
859
+ spec:
860
+ containers:
861
+ - name: keycloak
862
+ image: quay.io/keycloak/keycloak:26.2.3
863
+ args: ["start-dev", "--import-realm"]
864
+ env:
865
+ - name: KEYCLOAK_ADMIN
866
+ value: admin
867
+ - name: KEYCLOAK_ADMIN_PASSWORD
868
+ value: admin
869
+ - name: KC_DB
870
+ value: postgres
871
+ - name: KC_DB_URL
872
+ value: jdbc:postgresql://postgres:5432/keycloak
873
+ - name: KC_DB_USERNAME
874
+ value: "${config.datasource?.username || 'postgres'}"
875
+ - name: KC_DB_PASSWORD
876
+ value: "${config.datasource?.password || 'password'}"
877
+ ports:
878
+ - containerPort: 8080
879
+ volumeMounts:
880
+ - name: realm-volume
881
+ mountPath: /opt/keycloak/data/import/realm.json
882
+ subPath: realm.json
883
+ volumes:
884
+ - name: realm-volume
885
+ configMap:
886
+ name: keycloak-realm-config
887
+ ---
888
+ apiVersion: v1
889
+ kind: Service
890
+ metadata:
891
+ name: keycloak
892
+ spec:
893
+ ports:
894
+ - port: 8080
895
+ selector:
896
+ app: keycloak
897
+ `;
898
+
403
899
  const realmConfigDir = path.join(devopsDir, 'keycloak', 'realm-config');
404
900
  await fs.ensureDir(realmConfigDir);
405
901
  await fs.writeFile(path.join(realmConfigDir, `${realmName}-realm.json`), realmJson);
@@ -413,8 +909,102 @@ jobs:
413
909
  await fs.writeFile(path.join(devopsDir, 'app.yml'), appYaml);
414
910
  await fs.writeFile(path.join(devopsDir, 'docker-compose.yml'), dockerCompose);
415
911
  await fs.writeFile(path.join(k8sDir, 'mosquitto.conf'), mosquittoConf);
912
+
913
+ // Write Kubernetes manifest assets
914
+ await fs.writeFile(path.join(k8sDir, 'app.yaml'), k8sAppYaml);
915
+ await fs.writeFile(path.join(k8sDir, 'postgres.yaml'), k8sPostgresYaml);
916
+ await fs.writeFile(path.join(k8sDir, 'redis.yaml'), k8sRedisYaml);
917
+ await fs.writeFile(path.join(k8sDir, 'nats.yaml'), k8sNatsYaml);
918
+ await fs.writeFile(path.join(k8sDir, 'mosquitto.yaml'), k8sMosquittoYaml);
919
+ await fs.writeFile(path.join(k8sDir, 'elasticsearch.yaml'), k8sElasticsearchYaml);
920
+ await fs.writeFile(path.join(k8sDir, 'jaeger.yaml'), k8sJaegerYaml);
921
+ await fs.writeFile(path.join(k8sDir, 'otel-collector-k8s.yaml'), k8sOtelCollectorYaml);
922
+ await fs.writeFile(path.join(k8sDir, 'keycloak.yaml'), k8sKeycloakYaml);
923
+
924
+ // Additional optional services manifests
925
+ const k8sMongoYaml = `apiVersion: apps/v1
926
+ kind: Deployment
927
+ metadata:
928
+ name: mongodb
929
+ labels:
930
+ app: mongodb
931
+ spec:
932
+ replicas: 1
933
+ selector:
934
+ matchLabels:
935
+ app: mongodb
936
+ template:
937
+ metadata:
938
+ labels:
939
+ app: mongodb
940
+ spec:
941
+ containers:
942
+ - name: mongodb
943
+ image: mongo:7.0.5
944
+ ports:
945
+ - containerPort: 27017
946
+ ---
947
+ apiVersion: v1
948
+ kind: Service
949
+ metadata:
950
+ name: mongodb
951
+ spec:
952
+ ports:
953
+ - port: 27017
954
+ selector:
955
+ app: mongodb`;
956
+ const k8sMinioYaml = `apiVersion: apps/v1
957
+ kind: Deployment
958
+ metadata:
959
+ name: minio
960
+ labels:
961
+ app: minio
962
+ spec:
963
+ replicas: 1
964
+ selector:
965
+ matchLabels:
966
+ app: minio
967
+ template:
968
+ metadata:
969
+ labels:
970
+ app: minio
971
+ spec:
972
+ containers:
973
+ - name: minio
974
+ image: minio/minio:RELEASE.2024-05-10T19-05-27Z
975
+ args:
976
+ - server
977
+ - /data
978
+ env:
979
+ - name: MINIO_ROOT_USER
980
+ value: "minioadmin"
981
+ - name: MINIO_ROOT_PASSWORD
982
+ value: "minioadmin"
983
+ ports:
984
+ - containerPort: 9000
985
+ ---
986
+ apiVersion: v1
987
+ kind: Service
988
+ metadata:
989
+ name: minio
990
+ spec:
991
+ ports:
992
+ - port: 9000
993
+ selector:
994
+ app: minio`;
995
+ await fs.writeFile(path.join(k8sDir, 'mongodb.yaml'), k8sMongoYaml);
996
+ await fs.writeFile(path.join(k8sDir, 'minio.yaml'), k8sMinioYaml);
997
+
416
998
  await fs.writeFile(path.join(githubDir, 'ci.yml'), ciWorkflow);
417
999
  await fs.writeFile(path.join(githubDir, 'cd.yml'), cdWorkflow);
418
1000
 
419
- console.log(chalk.gray(' Generated devops/Dockerfile, devops/services.yml, devops/app.yml, devops/docker-compose.yml & GitHub Actions CI/CD'));
1001
+ const pushScriptPath = path.join(projectRootDir, 'push.sh');
1002
+ await fs.writeFile(pushScriptPath, pushScript);
1003
+ try {
1004
+ await fs.chmod(pushScriptPath, 0o755);
1005
+ } catch (e) {
1006
+ // Safe fallback for OS environments where chmod is not supported
1007
+ }
1008
+
1009
+ console.log(chalk.gray(' Generated devops/Dockerfile, devops/services.yml, devops/app.yml, devops/docker-compose.yml, push.sh, Kubernetes manifests & GitHub Actions CI/CD'));
420
1010
  };
@@ -21,7 +21,7 @@ import (
21
21
  "time"
22
22
 
23
23
  "github.com/gin-gonic/gin"
24
- "github.com/golang-jwt/jwt/v4"
24
+ "github.com/golang-jwt/jwt/v5"
25
25
  "{{app_name}}/config"
26
26
  )
27
27
 
@@ -164,7 +164,7 @@ func JWTMiddleware() gin.HandlerFunc {
164
164
  return nil, fmt.Errorf("missing kid header")
165
165
  }
166
166
  return GetPublicKeyByKid(kid, config.GetConfig())
167
- })
167
+ }, jwt.WithLeeway(10*time.Second))
168
168
 
169
169
  if err != nil || !token.Valid {
170
170
  c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "go-duck-cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "The Ultimate Evolutionary Go Microservice Scaffolder.",
5
5
  "main": "index.js",
6
6
  "type": "module",