Automatically deploy and update workers

Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
ItalyPaleAle 2022-12-12 22:53:35 +00:00
parent 456caaef6a
commit adc70a0143
6 changed files with 942 additions and 117 deletions

View File

@ -23,7 +23,9 @@ import (
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/textproto"
"net/url"
"regexp"
"strconv"
@ -33,9 +35,12 @@ import (
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/mitchellh/mapstructure"
"k8s.io/utils/strings/slices"
"github.com/dapr/components-contrib/bindings"
cfworkercode "github.com/dapr/components-contrib/internal/component/cloudflare/worker-src/dist"
"github.com/dapr/kit/logger"
"github.com/dapr/kit/ptr"
)
const (
@ -45,6 +50,9 @@ const (
tokenIssuer = "dapr.io/cloudflare"
// JWT token expiration
tokenExpiration = 5 * time.Minute
// Link to the documentation for the component
// TODO: Add link to docs
componentDocsUrl = "https://TODO"
)
// CFQueues is a binding for publishing messages on Cloudflare Queues
@ -78,15 +86,231 @@ func (q *CFQueues) Init(metadata bindings.Metadata) error {
Timeout: time.Second * 30,
}
// TODO: Automatically create or update the worker
ok, err := q.checkWorker()
if err != nil {
q.logger.Errorf("The component could not be initialized because of an error: %v", err)
return err
// Check if we're using an externally-managed worker
if q.metadata.WorkerURL != "" {
q.logger.Info("Using externally-managed worker: " + q.metadata.WorkerURL)
err = q.checkWorker(q.metadata.WorkerURL)
if err != nil {
q.logger.Errorf("The component could not be initialized because the externally-managed worker cannot be used: %v", err)
return err
}
} else {
// We are using a Dapr-managed worker, so let's check if it exists or needs to be created or updated
err = q.setupWorker()
if err != nil {
q.logger.Errorf("The component could not be initialized because the worker cannot be created or updated: %v", err)
return err
}
}
if !ok {
q.logger.Errorf("The worker is running but it's on an old version and needs to be upgraded")
return errors.New("worker needs to be upgraded")
return nil
}
// Creates or upgrades the worker that is managed by Dapr.
func (q *CFQueues) setupWorker() error {
// First, get the subdomain for the worker
// This also acts as a check for the API key
subdomain, err := q.getWorkersSubdomain()
if err != nil {
return fmt.Errorf("error retrieving the workers subdomain from the Cloudflare APIs: %w", err)
}
// Check if the worker exists and it's the supported version
// In case of error, any error, we will re-deploy the worker
workerUrl := fmt.Sprintf("https://%s.%s.workers.dev/", q.metadata.WorkerName, subdomain)
err = q.checkWorker(workerUrl)
if err != nil {
q.logger.Infof("Deploying updated worker at URL '%s'", workerUrl)
err = q.deployWorker()
if err != nil {
return fmt.Errorf("error deploying or updating the worker with the Cloudflare APIs: %w", err)
}
// Ensure the workers.dev route is enabled for the worker
err = q.enableWorkersDevRoute()
if err != nil {
return fmt.Errorf("error enabling the workers.dev route for the worker: %w", err)
}
q.logger.Infof("Deployed a new version of the worker at '%s'; note: it may take up to 30s for changes to propagate", workerUrl)
} else {
q.logger.Infof("Using worker at URL '%s'", workerUrl)
}
// Update the URL of the worker
q.metadata.WorkerURL = workerUrl
return nil
}
type cfGetWorkersSubdomainResponse struct {
Result struct {
Subdomain string `json:"subdomain"`
}
}
func (q *CFQueues) getWorkersSubdomain() (string, error) {
ctx, cancel := context.WithTimeout(q.ctx, 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.cloudflare.com/client/v4/accounts/"+q.metadata.CfAccountID+"/workers/subdomain", nil)
if err != nil {
return "", fmt.Errorf("error creating network request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+q.metadata.CfAPIToken)
req.Header.Set("Content-Type", "application/json")
res, err := q.client.Do(req)
if err != nil {
return "", fmt.Errorf("error invoking the service: %w", err)
}
defer func() {
// Drain the body before closing it
_, _ = io.ReadAll(res.Body)
res.Body.Close()
}()
if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("invalid response status code: %d", res.StatusCode)
}
var data cfGetWorkersSubdomainResponse
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
return "", fmt.Errorf("invalid response format: %w", err)
}
if data.Result.Subdomain == "" {
return "", fmt.Errorf("response does not contain a value for 'subdomain'")
}
return data.Result.Subdomain, nil
}
type deployWorkerMetadata struct {
Main string `json:"main_module"`
CompatibilityDate string `json:"compatibility_date"`
UsageModel string `json:"usage_model"`
Bindings []deployWorkerMetadata_Binding `json:"bindings,omitempty"`
}
type deployWorkerMetadata_Binding struct {
Name string `json:"name"`
Type string `json:"type"`
Text *string `json:"text,omitempty"`
QueueName *string `json:"queue_name,omitempty"`
}
func (q *CFQueues) deployWorker() error {
// Get the public part of the key as PEM-encoded
pubKey := q.metadata.privKey.Public()
pubKeyDer, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
return fmt.Errorf("failed to marshal public key to PKIX: %w", err)
}
publicKeyPem := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: pubKeyDer,
})
// Request body
buf := &bytes.Buffer{}
mpw := multipart.NewWriter(buf)
mh := textproto.MIMEHeader{}
// Script module
mh.Set("Content-Type", "application/javascript+module")
mh.Set("Content-Disposition", `form-data; name="worker.js"; filename="worker.js"`)
field, err := mpw.CreatePart(mh)
if err != nil {
return fmt.Errorf("failed to create field worker.js: %w", err)
}
_, err = field.Write(cfworkercode.WorkerScript)
if err != nil {
return fmt.Errorf("failed to write field worker.js: %w", err)
}
// Metadata
mh.Set("Content-Type", "application/json")
mh.Set("Content-Disposition", `form-data; name="metadata"; filename="metadata.json"`)
field, err = mpw.CreateFormField("metadata")
if err != nil {
return fmt.Errorf("failed to create field metadata: %w", err)
}
metadata := deployWorkerMetadata{
Main: "worker.js",
CompatibilityDate: cfworkercode.CompatibilityDate,
UsageModel: cfworkercode.UsageModel,
Bindings: []deployWorkerMetadata_Binding{
// Variables
{Type: "plain_text", Name: "PUBLIC_KEY", Text: ptr.Of(string(publicKeyPem))},
{Type: "plain_text", Name: "TOKEN_AUDIENCE", Text: &q.metadata.WorkerName},
// Queues
{Type: "queue", Name: q.metadata.QueueName, QueueName: &q.metadata.QueueName},
},
}
enc := json.NewEncoder(field)
enc.SetEscapeHTML(false)
err = enc.Encode(&metadata)
if err != nil {
return fmt.Errorf("failed to encode metadata as JSON: %w", err)
}
// Complete the body
err = mpw.Close()
if err != nil {
return fmt.Errorf("failed to close multipart body: %w", err)
}
// Make the request
ctx, cancel := context.WithTimeout(q.ctx, 30*time.Second)
defer cancel()
u := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/workers/scripts/%s", q.metadata.CfAccountID, q.metadata.WorkerName)
req, err := http.NewRequestWithContext(ctx, "PUT", u, buf)
if err != nil {
return fmt.Errorf("error creating network request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+q.metadata.CfAPIToken)
req.Header.Set("Content-Type", mpw.FormDataContentType())
res, err := q.client.Do(req)
if err != nil {
return fmt.Errorf("error invoking the service: %w", err)
}
defer func() {
// Drain the body before closing it
_, _ = io.ReadAll(res.Body)
res.Body.Close()
}()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("invalid response status code: %d", res.StatusCode)
}
return nil
}
func (q *CFQueues) enableWorkersDevRoute() error {
ctx, cancel := context.WithTimeout(q.ctx, 30*time.Second)
defer cancel()
u := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/workers/scripts/%s/subdomain", q.metadata.CfAccountID, q.metadata.WorkerName)
req, err := http.NewRequestWithContext(ctx, "POST", u, strings.NewReader(`{"enabled": true}`))
if err != nil {
return fmt.Errorf("error creating network request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+q.metadata.CfAPIToken)
req.Header.Set("Content-Type", "application/json")
res, err := q.client.Do(req)
if err != nil {
return fmt.Errorf("error invoking the service: %w", err)
}
defer func() {
// Drain the body before closing it
_, _ = io.ReadAll(res.Body)
res.Body.Close()
}()
if res.StatusCode != http.StatusOK {
return fmt.Errorf("invalid response status code: %d", res.StatusCode)
}
return nil
@ -97,26 +321,25 @@ type infoEndpointResponse struct {
Queues []string `json:"queues"`
}
// Check the worker to ensure it's available and it's using a supported version.
// In case the worker needs to be updated, the method returns false and no error
func (q *CFQueues) checkWorker() (bool, error) {
// Check a worker to ensure it's available and it's using a supported version.
func (q *CFQueues) checkWorker(workerURL string) error {
token, err := q.createToken()
if err != nil {
return false, fmt.Errorf("failed to create authorization token: %w", err)
return fmt.Errorf("failed to create authorization token: %w", err)
}
ctx, cancel := context.WithTimeout(q.ctx, 30*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", q.metadata.WorkerURL+".well-known/dapr/info", nil)
req, err := http.NewRequestWithContext(ctx, "GET", workerURL+".well-known/dapr/info", nil)
if err != nil {
return false, fmt.Errorf("error creating network request: %w", err)
return fmt.Errorf("error creating network request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+token)
res, err := q.client.Do(req)
if err != nil {
return false, fmt.Errorf("error invoking the worker: %w", err)
return fmt.Errorf("error invoking the worker: %w", err)
}
defer func() {
// Drain the body before closing it
@ -124,22 +347,25 @@ func (q *CFQueues) checkWorker() (bool, error) {
res.Body.Close()
}()
if res.StatusCode != http.StatusOK {
return false, fmt.Errorf("invalid response status code: %d", res.StatusCode)
return fmt.Errorf("invalid response status code: %d", res.StatusCode)
}
var data infoEndpointResponse
err = json.NewDecoder(res.Body).Decode(&data)
if err != nil {
return false, fmt.Errorf("invalid response from the worker: %w", err)
return fmt.Errorf("invalid response from the worker: %w", err)
}
version, _ := strconv.Atoi(data.Version)
if version < minWorkerVersion {
// Return no error indicating that the version is too low
return false, nil
return fmt.Errorf("the worker is running an outdated version '%d'; please upgrade the worker per instructions in the documentation at %s", version, componentDocsUrl)
}
return true, nil
if !slices.Contains(data.Queues, q.metadata.QueueName) {
return fmt.Errorf("the worker is not bound to the queue '%s'; please re-deploy the worker with the correct bindings per instructions in the documentation at %s", q.metadata.QueueName, componentDocsUrl)
}
return nil
}
// Operations returns the supported operations for this binding.
@ -159,12 +385,6 @@ func (q *CFQueues) Invoke(ctx context.Context, req *bindings.InvokeRequest) (*bi
// Handler for invoke operations for publishing messages to the Workers Queue
func (q *CFQueues) invokePublish(parentCtx context.Context, ir *bindings.InvokeRequest) (*bindings.InvokeResponse, error) {
md := publishRequestMetadata{}
err := md.FromMetadata(ir.Metadata)
if err != nil {
return nil, fmt.Errorf("invalid request: %w", err)
}
token, err := q.createToken()
if err != nil {
return nil, fmt.Errorf("failed to create authorization token: %w", err)
@ -178,7 +398,7 @@ func (q *CFQueues) invokePublish(parentCtx context.Context, ir *bindings.InvokeR
ir.Data = []byte(d)
}
req, err := http.NewRequestWithContext(ctx, "POST", q.metadata.WorkerURL+"publish/"+md.QueueName, bytes.NewReader(ir.Data))
req, err := http.NewRequestWithContext(ctx, "POST", q.metadata.WorkerURL+"publish/"+q.metadata.QueueName, bytes.NewReader(ir.Data))
if err != nil {
return nil, fmt.Errorf("error creating network request: %w", err)
}
@ -230,38 +450,57 @@ func (q *CFQueues) Close() error {
return nil
}
// Component metadata struct.
// The component can be initialized in two ways:
// - Instantiate the component with a "workerURL": assumes a worker that has been pre-deployed and it's ready to be used; we will not need API tokens
// - Instantiate the component with a "cfAPIToken" and "cfAccountID": Dapr will take care of creating the worker if it doesn't exist (or upgrade it if needed)
type componentMetadata struct {
WorkerURL string `mapstructure:"workerUrl"`
Key string `mapstructure:"key"`
WorkerName string `mapstructure:"workerName"`
QueueName string `mapstructure:"queueName"`
WorkerURL string `mapstructure:"workerUrl"`
CfAPIToken string `mapstructure:"cfAPIToken"`
CfAccountID string `mapstructure:"cfAccountID"`
Key string `mapstructure:"key"`
WorkerName string `mapstructure:"workerName"`
privKey ed25519.PrivateKey
}
// Validate the metadata object
var queueNameValidation = regexp.MustCompile("^([a-zA-Z0-9_\\-\\.]+)$")
// Validate the metadata object.
func (m *componentMetadata) Validate() error {
// Option 1: check if we have a workerURL
if m.WorkerURL != "" {
u, err := url.Parse(m.WorkerURL)
if err != nil {
return fmt.Errorf("invalid property 'workerUrl': %w", err)
}
if u.Scheme != "https" && u.Scheme != "http" {
return errors.New("invalid property 'workerUrl': unsupported scheme")
}
// Re-set the URL to make sure it's sanitized
m.WorkerURL = u.String()
if !strings.HasSuffix(m.WorkerURL, "/") {
m.WorkerURL += "/"
}
} else if m.CfAPIToken == "" || m.CfAccountID == "" {
// Option 2: we need cfAPIToken and cfAccountID
return errors.New("invalid component metadata: either 'workerUrl' or the combination of 'cfAPIToken'/'cfAccountID' is required")
}
// QueueName
if m.QueueName == "" {
return errors.New("property 'queueName' is required")
}
if !queueNameValidation.MatchString(m.QueueName) {
return errors.New("metadata property 'queueName' is invalid")
}
// WorkerName
if m.WorkerName == "" {
return errors.New("property 'workerName' is required")
}
// WorkerURL
if m.WorkerURL == "" {
return errors.New("property 'workerUrl' is required")
}
u, err := url.Parse(m.WorkerURL)
if err != nil {
return fmt.Errorf("invalid property 'workerUrl': %w", err)
}
if u.Scheme != "https" && u.Scheme != "http" {
return errors.New("invalid property 'workerUrl': unsupported scheme")
}
// Re-set the URL to make sure it's sanitized
m.WorkerURL = u.String()
if !strings.HasSuffix(m.WorkerURL, "/") {
m.WorkerURL += "/"
}
// Key
if m.Key == "" {
return errors.New("property 'key' is required")
@ -285,25 +524,3 @@ func (m *componentMetadata) Validate() error {
return nil
}
type publishRequestMetadata struct {
QueueName string
}
var queueNameValidation = regexp.MustCompile("^([a-zA-Z0-9_\\-\\.]+)$")
func (m *publishRequestMetadata) FromMetadata(md map[string]string) error {
if len(md) == 0 {
return errors.New("metata property 'queue' is required")
}
m.QueueName = md["queue"]
if m.QueueName == "" {
return errors.New("metata property 'queue' is required")
}
if !queueNameValidation.MatchString(m.QueueName) {
return errors.New("metadata property 'queue' is invalid")
}
return nil
}

View File

@ -143,7 +143,6 @@ out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/

View File

@ -0,0 +1,30 @@
/*
Copyright 2022 The Dapr Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cfworkercode
import (
// Allow using go:embed
_ "embed"
)
// Contains the source code for the worker.
//
//go:embed worker.js
var WorkerScript []byte
// Value for compatibility_date.
const CompatibilityDate = "2022-12-09"
// Value for usage_model.
const UsageModel = "bundled"

File diff suppressed because one or more lines are too long

View File

@ -14,6 +14,7 @@
},
"devDependencies": {
"@cloudflare/workers-types": "^4.20221111.1",
"esbuild": "^0.16.4",
"prettier": "^2.8.1",
"typescript": "^4.9.4",
"wrangler": "^2.6.2"
@ -56,6 +57,358 @@
"esbuild": "*"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.4.tgz",
"integrity": "sha512-rZzb7r22m20S1S7ufIc6DC6W659yxoOrl7sKP1nCYhuvUlnCFHVSbATG4keGUtV8rDz11sRRDbWkvQZpzPaHiw==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.4.tgz",
"integrity": "sha512-VPuTzXFm/m2fcGfN6CiwZTlLzxrKsWbPkG7ArRFpuxyaHUm/XFHQPD4xNwZT6uUmpIHhnSjcaCmcla8COzmZ5Q==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.4.tgz",
"integrity": "sha512-MW+B2O++BkcOfMWmuHXB15/l1i7wXhJFqbJhp82IBOais8RBEQv2vQz/jHrDEHaY2X0QY7Wfw86SBL2PbVOr0g==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.4.tgz",
"integrity": "sha512-a28X1O//aOfxwJVZVs7ZfM8Tyih2Za4nKJrBwW5Wm4yKsnwBy9aiS/xwpxiiTRttw3EaTg4Srerhcm6z0bu9Wg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.4.tgz",
"integrity": "sha512-e3doCr6Ecfwd7VzlaQqEPrnbvvPjE9uoTpxG5pyLzr2rI2NMjDHmvY1E5EO81O/e9TUOLLkXA5m6T8lfjK9yAA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.4.tgz",
"integrity": "sha512-Oup3G/QxBgvvqnXWrBed7xxkFNwAwJVHZcklWyQt7YCAL5bfUkaa6FVWnR78rNQiM8MqqLiT6ZTZSdUFuVIg1w==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.4.tgz",
"integrity": "sha512-vAP+eYOxlN/Bpo/TZmzEQapNS8W1njECrqkTpNgvXskkkJC2AwOXwZWai/Kc2vEFZUXQttx6UJbj9grqjD/+9Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.4.tgz",
"integrity": "sha512-A47ZmtpIPyERxkSvIv+zLd6kNIOtJH03XA0Hy7jaceRDdQaQVGSDt4mZqpWqJYgDk9rg96aglbF6kCRvPGDSUA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.4.tgz",
"integrity": "sha512-2zXoBhv4r5pZiyjBKrOdFP4CXOChxXiYD50LRUU+65DkdS5niPFHbboKZd/c81l0ezpw7AQnHeoCy5hFrzzs4g==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.4.tgz",
"integrity": "sha512-uxdSrpe9wFhz4yBwt2kl2TxS/NWEINYBUFIxQtaEVtglm1eECvsj1vEKI0KX2k2wCe17zDdQ3v+jVxfwVfvvjw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.4.tgz",
"integrity": "sha512-peDrrUuxbZ9Jw+DwLCh/9xmZAk0p0K1iY5d2IcwmnN+B87xw7kujOkig6ZRcZqgrXgeRGurRHn0ENMAjjD5DEg==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.4.tgz",
"integrity": "sha512-sD9EEUoGtVhFjjsauWjflZklTNr57KdQ6xfloO4yH1u7vNQlOfAlhEzbyBKfgbJlW7rwXYBdl5/NcZ+Mg2XhQA==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.4.tgz",
"integrity": "sha512-X1HSqHUX9D+d0l6/nIh4ZZJ94eQky8d8z6yxAptpZE3FxCWYWvTDd9X9ST84MGZEJx04VYUD/AGgciddwO0b8g==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.4.tgz",
"integrity": "sha512-97ANpzyNp0GTXCt6SRdIx1ngwncpkV/z453ZuxbnBROCJ5p/55UjhbaG23UdHj88fGWLKPFtMoU4CBacz4j9FA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.4.tgz",
"integrity": "sha512-pUvPQLPmbEeJRPjP0DYTC1vjHyhrnCklQmCGYbipkep+oyfTn7GTBJXoPodR7ZS5upmEyc8lzAkn2o29wD786A==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.4.tgz",
"integrity": "sha512-N55Q0mJs3Sl8+utPRPBrL6NLYZKBCLLx0bme/+RbjvMforTGGzFvsRl4xLTZMUBFC1poDzBEPTEu5nxizQ9Nlw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.4.tgz",
"integrity": "sha512-LHSJLit8jCObEQNYkgsDYBh2JrJT53oJO2HVdkSYLa6+zuLJh0lAr06brXIkljrlI+N7NNW1IAXGn/6IZPi3YQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.4.tgz",
"integrity": "sha512-nLgdc6tWEhcCFg/WVFaUxHcPK3AP/bh+KEwKtl69Ay5IBqUwKDaq/6Xk0E+fh/FGjnLwqFSsarsbPHeKM8t8Sw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.4.tgz",
"integrity": "sha512-08SluG24GjPO3tXKk95/85n9kpyZtXCVwURR2i4myhrOfi3jspClV0xQQ0W0PYWHioJj+LejFMt41q+PG3mlAQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.4.tgz",
"integrity": "sha512-yYiRDQcqLYQSvNQcBKN7XogbrSvBE45FEQdH8fuXPl7cngzkCvpsG2H9Uey39IjQ6gqqc+Q4VXYHsQcKW0OMjQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.4.tgz",
"integrity": "sha512-5rabnGIqexekYkh9zXG5waotq8mrdlRoBqAktjx2W3kb0zsI83mdCwrcAeKYirnUaTGztR5TxXcXmQrEzny83w==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.4.tgz",
"integrity": "sha512-sN/I8FMPtmtT2Yw+Dly8Ur5vQ5a/RmC8hW7jO9PtPSQUPkowxWpcUZnqOggU7VwyT3Xkj6vcXWd3V/qTXwultQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
@ -471,9 +824,9 @@
}
},
"node_modules/esbuild": {
"version": "0.14.51",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz",
"integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==",
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.4.tgz",
"integrity": "sha512-qQrPMQpPTWf8jHugLWHoGqZjApyx3OEm76dlTXobHwh/EBbavbRdjXdYi/GWr43GyN0sfpap14GPkb05NH3ROA==",
"dev": true,
"hasInstallScript": true,
"bin": {
@ -483,26 +836,28 @@
"node": ">=12"
},
"optionalDependencies": {
"esbuild-android-64": "0.14.51",
"esbuild-android-arm64": "0.14.51",
"esbuild-darwin-64": "0.14.51",
"esbuild-darwin-arm64": "0.14.51",
"esbuild-freebsd-64": "0.14.51",
"esbuild-freebsd-arm64": "0.14.51",
"esbuild-linux-32": "0.14.51",
"esbuild-linux-64": "0.14.51",
"esbuild-linux-arm": "0.14.51",
"esbuild-linux-arm64": "0.14.51",
"esbuild-linux-mips64le": "0.14.51",
"esbuild-linux-ppc64le": "0.14.51",
"esbuild-linux-riscv64": "0.14.51",
"esbuild-linux-s390x": "0.14.51",
"esbuild-netbsd-64": "0.14.51",
"esbuild-openbsd-64": "0.14.51",
"esbuild-sunos-64": "0.14.51",
"esbuild-windows-32": "0.14.51",
"esbuild-windows-64": "0.14.51",
"esbuild-windows-arm64": "0.14.51"
"@esbuild/android-arm": "0.16.4",
"@esbuild/android-arm64": "0.16.4",
"@esbuild/android-x64": "0.16.4",
"@esbuild/darwin-arm64": "0.16.4",
"@esbuild/darwin-x64": "0.16.4",
"@esbuild/freebsd-arm64": "0.16.4",
"@esbuild/freebsd-x64": "0.16.4",
"@esbuild/linux-arm": "0.16.4",
"@esbuild/linux-arm64": "0.16.4",
"@esbuild/linux-ia32": "0.16.4",
"@esbuild/linux-loong64": "0.16.4",
"@esbuild/linux-mips64el": "0.16.4",
"@esbuild/linux-ppc64": "0.16.4",
"@esbuild/linux-riscv64": "0.16.4",
"@esbuild/linux-s390x": "0.16.4",
"@esbuild/linux-x64": "0.16.4",
"@esbuild/netbsd-x64": "0.16.4",
"@esbuild/openbsd-x64": "0.16.4",
"@esbuild/sunos-x64": "0.16.4",
"@esbuild/win32-arm64": "0.16.4",
"@esbuild/win32-ia32": "0.16.4",
"@esbuild/win32-x64": "0.16.4"
}
},
"node_modules/esbuild-android-64": {
@ -1538,6 +1893,41 @@
"fsevents": "~2.3.2"
}
},
"node_modules/wrangler/node_modules/esbuild": {
"version": "0.14.51",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz",
"integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"esbuild-android-64": "0.14.51",
"esbuild-android-arm64": "0.14.51",
"esbuild-darwin-64": "0.14.51",
"esbuild-darwin-arm64": "0.14.51",
"esbuild-freebsd-64": "0.14.51",
"esbuild-freebsd-arm64": "0.14.51",
"esbuild-linux-32": "0.14.51",
"esbuild-linux-64": "0.14.51",
"esbuild-linux-arm": "0.14.51",
"esbuild-linux-arm64": "0.14.51",
"esbuild-linux-mips64le": "0.14.51",
"esbuild-linux-ppc64le": "0.14.51",
"esbuild-linux-riscv64": "0.14.51",
"esbuild-linux-s390x": "0.14.51",
"esbuild-netbsd-64": "0.14.51",
"esbuild-openbsd-64": "0.14.51",
"esbuild-sunos-64": "0.14.51",
"esbuild-windows-32": "0.14.51",
"esbuild-windows-64": "0.14.51",
"esbuild-windows-arm64": "0.14.51"
}
},
"node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
@ -1617,6 +2007,160 @@
"rollup-plugin-node-polyfills": "^0.2.1"
}
},
"@esbuild/android-arm": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.4.tgz",
"integrity": "sha512-rZzb7r22m20S1S7ufIc6DC6W659yxoOrl7sKP1nCYhuvUlnCFHVSbATG4keGUtV8rDz11sRRDbWkvQZpzPaHiw==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.4.tgz",
"integrity": "sha512-VPuTzXFm/m2fcGfN6CiwZTlLzxrKsWbPkG7ArRFpuxyaHUm/XFHQPD4xNwZT6uUmpIHhnSjcaCmcla8COzmZ5Q==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.4.tgz",
"integrity": "sha512-MW+B2O++BkcOfMWmuHXB15/l1i7wXhJFqbJhp82IBOais8RBEQv2vQz/jHrDEHaY2X0QY7Wfw86SBL2PbVOr0g==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.4.tgz",
"integrity": "sha512-a28X1O//aOfxwJVZVs7ZfM8Tyih2Za4nKJrBwW5Wm4yKsnwBy9aiS/xwpxiiTRttw3EaTg4Srerhcm6z0bu9Wg==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.4.tgz",
"integrity": "sha512-e3doCr6Ecfwd7VzlaQqEPrnbvvPjE9uoTpxG5pyLzr2rI2NMjDHmvY1E5EO81O/e9TUOLLkXA5m6T8lfjK9yAA==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.4.tgz",
"integrity": "sha512-Oup3G/QxBgvvqnXWrBed7xxkFNwAwJVHZcklWyQt7YCAL5bfUkaa6FVWnR78rNQiM8MqqLiT6ZTZSdUFuVIg1w==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.4.tgz",
"integrity": "sha512-vAP+eYOxlN/Bpo/TZmzEQapNS8W1njECrqkTpNgvXskkkJC2AwOXwZWai/Kc2vEFZUXQttx6UJbj9grqjD/+9Q==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.4.tgz",
"integrity": "sha512-A47ZmtpIPyERxkSvIv+zLd6kNIOtJH03XA0Hy7jaceRDdQaQVGSDt4mZqpWqJYgDk9rg96aglbF6kCRvPGDSUA==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.4.tgz",
"integrity": "sha512-2zXoBhv4r5pZiyjBKrOdFP4CXOChxXiYD50LRUU+65DkdS5niPFHbboKZd/c81l0ezpw7AQnHeoCy5hFrzzs4g==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.4.tgz",
"integrity": "sha512-uxdSrpe9wFhz4yBwt2kl2TxS/NWEINYBUFIxQtaEVtglm1eECvsj1vEKI0KX2k2wCe17zDdQ3v+jVxfwVfvvjw==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.4.tgz",
"integrity": "sha512-peDrrUuxbZ9Jw+DwLCh/9xmZAk0p0K1iY5d2IcwmnN+B87xw7kujOkig6ZRcZqgrXgeRGurRHn0ENMAjjD5DEg==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.4.tgz",
"integrity": "sha512-sD9EEUoGtVhFjjsauWjflZklTNr57KdQ6xfloO4yH1u7vNQlOfAlhEzbyBKfgbJlW7rwXYBdl5/NcZ+Mg2XhQA==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.4.tgz",
"integrity": "sha512-X1HSqHUX9D+d0l6/nIh4ZZJ94eQky8d8z6yxAptpZE3FxCWYWvTDd9X9ST84MGZEJx04VYUD/AGgciddwO0b8g==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.4.tgz",
"integrity": "sha512-97ANpzyNp0GTXCt6SRdIx1ngwncpkV/z453ZuxbnBROCJ5p/55UjhbaG23UdHj88fGWLKPFtMoU4CBacz4j9FA==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.4.tgz",
"integrity": "sha512-pUvPQLPmbEeJRPjP0DYTC1vjHyhrnCklQmCGYbipkep+oyfTn7GTBJXoPodR7ZS5upmEyc8lzAkn2o29wD786A==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.4.tgz",
"integrity": "sha512-N55Q0mJs3Sl8+utPRPBrL6NLYZKBCLLx0bme/+RbjvMforTGGzFvsRl4xLTZMUBFC1poDzBEPTEu5nxizQ9Nlw==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.4.tgz",
"integrity": "sha512-LHSJLit8jCObEQNYkgsDYBh2JrJT53oJO2HVdkSYLa6+zuLJh0lAr06brXIkljrlI+N7NNW1IAXGn/6IZPi3YQ==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.4.tgz",
"integrity": "sha512-nLgdc6tWEhcCFg/WVFaUxHcPK3AP/bh+KEwKtl69Ay5IBqUwKDaq/6Xk0E+fh/FGjnLwqFSsarsbPHeKM8t8Sw==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.4.tgz",
"integrity": "sha512-08SluG24GjPO3tXKk95/85n9kpyZtXCVwURR2i4myhrOfi3jspClV0xQQ0W0PYWHioJj+LejFMt41q+PG3mlAQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.4.tgz",
"integrity": "sha512-yYiRDQcqLYQSvNQcBKN7XogbrSvBE45FEQdH8fuXPl7cngzkCvpsG2H9Uey39IjQ6gqqc+Q4VXYHsQcKW0OMjQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.4.tgz",
"integrity": "sha512-5rabnGIqexekYkh9zXG5waotq8mrdlRoBqAktjx2W3kb0zsI83mdCwrcAeKYirnUaTGztR5TxXcXmQrEzny83w==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.4.tgz",
"integrity": "sha512-sN/I8FMPtmtT2Yw+Dly8Ur5vQ5a/RmC8hW7jO9PtPSQUPkowxWpcUZnqOggU7VwyT3Xkj6vcXWd3V/qTXwultQ==",
"dev": true,
"optional": true
},
"@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
@ -1946,31 +2490,33 @@
"dev": true
},
"esbuild": {
"version": "0.14.51",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz",
"integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==",
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.4.tgz",
"integrity": "sha512-qQrPMQpPTWf8jHugLWHoGqZjApyx3OEm76dlTXobHwh/EBbavbRdjXdYi/GWr43GyN0sfpap14GPkb05NH3ROA==",
"dev": true,
"requires": {
"esbuild-android-64": "0.14.51",
"esbuild-android-arm64": "0.14.51",
"esbuild-darwin-64": "0.14.51",
"esbuild-darwin-arm64": "0.14.51",
"esbuild-freebsd-64": "0.14.51",
"esbuild-freebsd-arm64": "0.14.51",
"esbuild-linux-32": "0.14.51",
"esbuild-linux-64": "0.14.51",
"esbuild-linux-arm": "0.14.51",
"esbuild-linux-arm64": "0.14.51",
"esbuild-linux-mips64le": "0.14.51",
"esbuild-linux-ppc64le": "0.14.51",
"esbuild-linux-riscv64": "0.14.51",
"esbuild-linux-s390x": "0.14.51",
"esbuild-netbsd-64": "0.14.51",
"esbuild-openbsd-64": "0.14.51",
"esbuild-sunos-64": "0.14.51",
"esbuild-windows-32": "0.14.51",
"esbuild-windows-64": "0.14.51",
"esbuild-windows-arm64": "0.14.51"
"@esbuild/android-arm": "0.16.4",
"@esbuild/android-arm64": "0.16.4",
"@esbuild/android-x64": "0.16.4",
"@esbuild/darwin-arm64": "0.16.4",
"@esbuild/darwin-x64": "0.16.4",
"@esbuild/freebsd-arm64": "0.16.4",
"@esbuild/freebsd-x64": "0.16.4",
"@esbuild/linux-arm": "0.16.4",
"@esbuild/linux-arm64": "0.16.4",
"@esbuild/linux-ia32": "0.16.4",
"@esbuild/linux-loong64": "0.16.4",
"@esbuild/linux-mips64el": "0.16.4",
"@esbuild/linux-ppc64": "0.16.4",
"@esbuild/linux-riscv64": "0.16.4",
"@esbuild/linux-s390x": "0.16.4",
"@esbuild/linux-x64": "0.16.4",
"@esbuild/netbsd-x64": "0.16.4",
"@esbuild/openbsd-x64": "0.16.4",
"@esbuild/sunos-x64": "0.16.4",
"@esbuild/win32-arm64": "0.16.4",
"@esbuild/win32-ia32": "0.16.4",
"@esbuild/win32-x64": "0.16.4"
}
},
"esbuild-android-64": {
@ -2610,6 +3156,36 @@
"selfsigned": "^2.0.1",
"source-map": "^0.7.4",
"xxhash-wasm": "^1.0.1"
},
"dependencies": {
"esbuild": {
"version": "0.14.51",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz",
"integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==",
"dev": true,
"requires": {
"esbuild-android-64": "0.14.51",
"esbuild-android-arm64": "0.14.51",
"esbuild-darwin-64": "0.14.51",
"esbuild-darwin-arm64": "0.14.51",
"esbuild-freebsd-64": "0.14.51",
"esbuild-freebsd-arm64": "0.14.51",
"esbuild-linux-32": "0.14.51",
"esbuild-linux-64": "0.14.51",
"esbuild-linux-arm": "0.14.51",
"esbuild-linux-arm64": "0.14.51",
"esbuild-linux-mips64le": "0.14.51",
"esbuild-linux-ppc64le": "0.14.51",
"esbuild-linux-riscv64": "0.14.51",
"esbuild-linux-s390x": "0.14.51",
"esbuild-netbsd-64": "0.14.51",
"esbuild-openbsd-64": "0.14.51",
"esbuild-sunos-64": "0.14.51",
"esbuild-windows-32": "0.14.51",
"esbuild-windows-64": "0.14.51",
"esbuild-windows-arm64": "0.14.51"
}
}
}
},
"ws": {

View File

@ -5,6 +5,7 @@
"version": "20221209",
"main": "worker.ts",
"scripts": {
"build": "esbuild --bundle --minify --outfile=./dist/worker.js --format=esm --platform=browser worker.ts",
"start": "wrangler dev --local",
"format": "prettier --write ."
},
@ -12,6 +13,7 @@
"license": "Apache2",
"devDependencies": {
"@cloudflare/workers-types": "^4.20221111.1",
"esbuild": "^0.16.4",
"prettier": "^2.8.1",
"typescript": "^4.9.4",
"wrangler": "^2.6.2"