11#!/usr/bin/env node
22
3- import os from 'os' ;
4- import childProcess from 'child_process' ;
3+ import os from 'node:os' ;
4+ import fs from 'node:fs' ;
5+ import url from 'node:url' ;
6+ import process from 'node:process' ;
7+ import childProcess from 'node:child_process' ;
8+ import TOML from '@iarna/toml' ;
9+ import $RefParser from '@apidevtools/json-schema-ref-parser' ;
510
611const platform = os . platform ( ) ;
712
13+ async function loadEnvSchema ( ) {
14+ const schema = await $RefParser . bundle ( 'env.schema.json' ) ;
15+ const props = new Set ( ) ;
16+ const required = new Set ( ) ;
17+ ( function extract ( s ) {
18+ if ( ! s || typeof s !== 'object' ) return ;
19+ // Collect properties
20+ if ( s . properties ) Object . keys ( s . properties ) . forEach ( ( k ) => props . add ( k ) ) ;
21+ // Collect required properties
22+ if ( s . required ) s . required . forEach ( ( r ) => required . add ( r ) ) ;
23+ // Process composition keywords
24+ [ 'allOf' , 'anyOf' , 'oneOf' ] . forEach (
25+ ( k ) => Array . isArray ( s [ k ] ) && s [ k ] . forEach ( extract ) ,
26+ ) ;
27+ } ) ( schema ) ;
28+ return {
29+ allKeys : [ ...props ] ,
30+ requiredKeys : [ ...required ] ,
31+ } ;
32+ }
33+
834/* eslint-disable no-console */
935async function main ( argv = process . argv ) {
1036 argv = argv . slice ( 2 ) ;
11- const deployArgs = [ 'deploy' , '--config' , './wrangler.toml' , ...argv ] ;
37+ // Optional feature is used for feature branches
38+ let feature ;
39+ const restArgs = [ ] ;
40+ while ( argv . length > 0 ) {
41+ const option = argv . shift ( ) ;
42+ let match ;
43+ if ( ( match = option . match ( / - - f e a t u r e (?: = ( .+ ) | $ ) / ) ) ) {
44+ feature = match [ 1 ] ?? argv . shift ( ) ;
45+ } else {
46+ restArgs . push ( option ) ;
47+ }
48+ }
49+ // The `--feature X` option only makes sense if you also use `--env X`.
50+ if ( typeof feature === 'string' ) {
51+ const wranglerConfig = TOML . parse (
52+ fs . readFileSync ( './wrangler.toml' , { encoding : 'utf-8' } ) ,
53+ ) ;
54+ // Backup the original wrangler.toml
55+ fs . renameSync ( './wrangler.toml' , './wrangler.toml.bak' ) ;
56+ // All the handlers for swapping back the original wrangler.toml
57+ process . on ( 'beforeExit' , ( ) => {
58+ try {
59+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
60+ } catch ( e ) {
61+ if ( e . code !== 'ENOENT' ) throw e ;
62+ }
63+ } ) ;
64+ process . on ( 'uncaughtException' , ( ) => {
65+ try {
66+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
67+ } catch ( e ) {
68+ if ( e . code !== 'ENOENT' ) throw e ;
69+ }
70+ } ) ;
71+ process . on ( 'unhandledRejection' , ( ) => {
72+ try {
73+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
74+ } catch ( e ) {
75+ if ( e . code !== 'ENOENT' ) throw e ;
76+ }
77+ } ) ;
78+ process . on ( 'SIGINT' , ( ) => {
79+ try {
80+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
81+ } catch ( e ) {
82+ if ( e . code !== 'ENOENT' ) throw e ;
83+ }
84+ } ) ;
85+ process . on ( 'SIGTERM' , ( ) => {
86+ try {
87+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
88+ } catch ( e ) {
89+ if ( e . code !== 'ENOENT' ) throw e ;
90+ }
91+ } ) ;
92+ process . on ( 'SIGQUIT' , ( ) => {
93+ try {
94+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
95+ } catch ( e ) {
96+ if ( e . code !== 'ENOENT' ) throw e ;
97+ }
98+ } ) ;
99+ process . on ( 'SIGHUP' , ( ) => {
100+ try {
101+ fs . renameSync ( './wrangler.toml.bak' , './wrangler.toml' ) ;
102+ } catch ( e ) {
103+ if ( e . code !== 'ENOENT' ) throw e ;
104+ }
105+ } ) ;
106+ // Add in the feature environment
107+ wranglerConfig . env [ feature ] = {
108+ name : `${ wranglerConfig . name } -${ feature } ` ,
109+ routes : wranglerConfig . routes . map ( ( r ) => ( {
110+ pattern : `${ feature } .${ r . pattern } ` ,
111+ custom_domain : true ,
112+ } ) ) ,
113+ durable_objects : {
114+ bindings : [ ...( wranglerConfig . durable_objects ?. bindings ?? [ ] ) ] ,
115+ } ,
116+ migrations : [ ...( wranglerConfig . migrations ?? [ ] ) ] ,
117+ } ;
118+ fs . writeFileSync ( './wrangler.toml' , TOML . stringify ( wranglerConfig ) , {
119+ encoding : 'utf-8' ,
120+ } ) ;
121+ }
122+ const { allKeys, requiredKeys } = await loadEnvSchema ( ) ;
123+ // Check if required variables are set
124+ for ( const key of requiredKeys ) {
125+ if ( process . env [ key ] == null || process . env [ key ] === '' ) {
126+ throw new Error ( `Required environment variable ${ key } is not set` ) ;
127+ }
128+ }
129+ const secretBulkArgs = [
130+ 'secret' ,
131+ 'bulk' ,
132+ '--config' ,
133+ './wrangler.toml' ,
134+ ...restArgs ,
135+ ] ;
136+ console . error ( [ 'wrangler' , ...secretBulkArgs ] . join ( ' ' ) ) ;
137+ const secrets = { } ;
138+ for ( const key of allKeys ) {
139+ secrets [ key ] = process . env [ key ] ;
140+ }
141+ childProcess . execFileSync ( 'wrangler' , secretBulkArgs , {
142+ input : JSON . stringify ( secrets ) ,
143+ } ) ;
144+ const deployArgs = [ 'deploy' , '--config' , './wrangler.toml' , ...restArgs ] ;
12145 console . error ( [ 'wrangler' , ...deployArgs ] . join ( ' ' ) ) ;
13146 childProcess . execFileSync ( 'wrangler' , deployArgs , {
14147 stdio : [ 'inherit' , 'inherit' , 'inherit' ] ,
@@ -19,4 +152,9 @@ async function main(argv = process.argv) {
19152}
20153/* eslint-enable no-console */
21154
22- void main ( ) ;
155+ if ( import . meta. url . startsWith ( 'file:' ) ) {
156+ const modulePath = url . fileURLToPath ( import . meta. url ) ;
157+ if ( process . argv [ 1 ] === modulePath ) {
158+ void main ( ) ;
159+ }
160+ }
0 commit comments